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);
1268 /* case 1: // Not supported yet
1270 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1275 ret=ret || (newType!=type);
1276 conn[newPos]=newType;
1278 posOfCurCell=index[i+1];
1283 std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1284 newPos+=lgthOfCurCell;
1285 posOfCurCell+=lgthOfCurCell;
1289 if(newPos!=initMeshLgth)
1290 _nodal_connec->reAlloc(newPos);
1297 * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1298 * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1299 * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells.
1301 * \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
1304 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1306 checkFullyDefined();
1307 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1308 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1309 MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1310 coords->recenterForMaxPrecision(eps);
1312 mcIdType nbOfCells=getNumberOfCells();
1313 const mcIdType *conn=_nodal_connec->getConstPointer();
1314 const mcIdType *index=_nodal_connec_index->getConstPointer();
1315 MCAuto<DataArrayIdType> connINew=DataArrayIdType::New();
1316 connINew->alloc(nbOfCells+1,1);
1317 mcIdType *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1318 MCAuto<DataArrayIdType> connNew=DataArrayIdType::New(); connNew->alloc(0,1);
1319 MCAuto<DataArrayIdType> E_Fi(DataArrayIdType::New()), E_F(DataArrayIdType::New()), F_Ei(DataArrayIdType::New()), F_E(DataArrayIdType::New());
1320 MCAuto<MEDCouplingUMesh> m_faces(buildDescendingConnectivity(E_F, E_Fi, F_E, F_Ei));
1322 for(mcIdType i=0;i<nbOfCells;i++,connINewPtr++)
1324 if(conn[index[i]]==ToIdType(INTERP_KERNEL::NORM_POLYHED))
1326 SimplifyPolyhedronCell(eps,coords, i,connNew, m_faces, E_Fi, E_F, F_Ei, F_E);
1330 connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1331 *connINewPtr=connNew->getNumberOfTuples();
1334 setConnectivity(connNew,connINew,false);
1338 * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1339 * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1340 * the format of the returned DataArrayIdType instance.
1342 * \return a newly allocated DataArrayIdType sorted ascendingly of fetched node ids.
1343 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1345 DataArrayIdType *MEDCouplingUMesh::computeFetchedNodeIds() const
1347 checkConnectivityFullyDefined();
1348 const mcIdType *maxEltPt(std::max_element(_nodal_connec->begin(),_nodal_connec->end()));
1349 mcIdType maxElt(maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1);
1350 std::vector<bool> retS(maxElt,false);
1351 computeNodeIdsAlg(retS);
1352 return DataArrayIdType::BuildListOfSwitchedOn(retS);
1356 * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1357 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1359 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1361 mcIdType nbOfNodes=ToIdType(nodeIdsInUse.size()),
1362 nbOfCells=getNumberOfCells();
1363 const mcIdType *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1364 for(mcIdType i=0;i<nbOfCells;i++)
1365 for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1368 if(conn[j]<nbOfNodes)
1369 nodeIdsInUse[conn[j]]=true;
1372 std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1373 throw INTERP_KERNEL::Exception(oss.str());
1380 struct MEDCouplingAccVisit
1382 MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1383 mcIdType operator()(mcIdType val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1384 mcIdType _new_nb_of_nodes;
1390 * Finds nodes not used in any cell and returns an array giving a new id to every node
1391 * by excluding the unused nodes, for which the array holds -1. The result array is
1392 * a mapping in "Old to New" mode.
1393 * \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1394 * \return DataArrayIdType * - a new instance of DataArrayIdType. Its length is \a
1395 * this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1396 * if the node is unused or a new id else. The caller is to delete this
1397 * array using decrRef() as it is no more needed.
1398 * \throw If the coordinates array is not set.
1399 * \throw If the nodal connectivity of cells is not defined.
1400 * \throw If the nodal connectivity includes an invalid id.
1402 * \if ENABLE_EXAMPLES
1403 * \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1404 * \ref py_mcumesh_getNodeIdsInUse "Here is a Python example".
1406 * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1408 DataArrayIdType *MEDCouplingUMesh::getNodeIdsInUse(mcIdType& nbrOfNodesInUse) const
1411 mcIdType nbOfNodes(getNumberOfNodes());
1412 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1413 ret->alloc(nbOfNodes,1);
1414 mcIdType *traducer=ret->getPointer();
1415 std::fill(traducer,traducer+nbOfNodes,-1);
1416 mcIdType nbOfCells=getNumberOfCells();
1417 const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
1418 const mcIdType *conn=_nodal_connec->getConstPointer();
1419 for(mcIdType i=0;i<nbOfCells;i++)
1420 for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1423 if(conn[j]<nbOfNodes)
1424 traducer[conn[j]]=1;
1427 std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1428 throw INTERP_KERNEL::Exception(oss.str());
1431 nbrOfNodesInUse=ToIdType(std::count(traducer,traducer+nbOfNodes,1));
1432 std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1437 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1438 * For each cell in \b this the number of nodes constituting cell is computed.
1439 * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1440 * So for pohyhedrons some nodes can be counted several times in the returned result.
1442 * \return a newly allocated array
1443 * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1445 DataArrayIdType *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1447 checkConnectivityFullyDefined();
1448 mcIdType nbOfCells=getNumberOfCells();
1449 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1450 ret->alloc(nbOfCells,1);
1451 mcIdType *retPtr=ret->getPointer();
1452 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1453 const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1454 for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1456 if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1457 *retPtr=connI[i+1]-connI[i]-1;
1459 *retPtr=connI[i+1]-connI[i]-1-ToIdType(std::count(conn+connI[i]+1,conn+connI[i+1],-1));
1465 * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1466 * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1468 * \return DataArrayIdType * - new object to be deallocated by the caller.
1469 * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1471 DataArrayIdType *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1473 checkConnectivityFullyDefined();
1474 mcIdType nbOfCells=getNumberOfCells();
1475 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1476 ret->alloc(nbOfCells,1);
1477 mcIdType *retPtr=ret->getPointer();
1478 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1479 const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1480 for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1482 std::set<mcIdType> s(conn+connI[i]+1,conn+connI[i+1]);
1483 if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1484 *retPtr=ToIdType(s.size());
1488 *retPtr=ToIdType(s.size());
1495 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1496 * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1498 * \return a newly allocated array
1500 DataArrayIdType *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1502 checkConnectivityFullyDefined();
1503 mcIdType nbOfCells=getNumberOfCells();
1504 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1505 ret->alloc(nbOfCells,1);
1506 mcIdType *retPtr=ret->getPointer();
1507 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1508 const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1509 for(mcIdType i=0;i<nbOfCells;i++,retPtr++,connI++)
1511 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1512 *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1518 * Removes unused nodes (the node coordinates array is shorten) and returns an array
1519 * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1520 * array mean that the corresponding old node is no more used.
1521 * \return DataArrayIdType * - a new instance of DataArrayIdType of length \a
1522 * this->getNumberOfNodes() before call of this method. The caller is to
1523 * delete this array using decrRef() as it is no more needed.
1524 * \throw If the coordinates array is not set.
1525 * \throw If the nodal connectivity of cells is not defined.
1526 * \throw If the nodal connectivity includes an invalid id.
1527 * \sa areAllNodesFetched
1529 * \if ENABLE_EXAMPLES
1530 * \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1531 * \ref py_mcumesh_zipCoordsTraducer "Here is a Python example".
1534 DataArrayIdType *MEDCouplingUMesh::zipCoordsTraducer()
1536 return MEDCouplingPointSet::zipCoordsTraducer();
1540 * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1541 * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1543 int MEDCouplingUMesh::AreCellsEqual(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2, int compType)
1548 return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1550 return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1552 return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1554 return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1556 return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1558 throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1562 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1564 int MEDCouplingUMesh::AreCellsEqualPolicy0(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1566 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1567 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1572 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1574 int MEDCouplingUMesh::AreCellsEqualPolicy1(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1576 mcIdType sz=connI[cell1+1]-connI[cell1];
1577 if(sz==connI[cell2+1]-connI[cell2])
1579 if(conn[connI[cell1]]==conn[connI[cell2]])
1581 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1582 unsigned dim=cm.getDimension();
1587 mcIdType sz1=2*(sz-1);
1588 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1589 mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1590 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1591 work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1592 return work!=tmp+sz1?1:0;
1595 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1598 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1605 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1607 int MEDCouplingUMesh::AreCellsEqualPolicy2(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1609 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1611 if(conn[connI[cell1]]==conn[connI[cell2]])
1613 std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1614 std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1622 * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1624 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1626 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1628 std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1629 std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1636 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1638 int MEDCouplingUMesh::AreCellsEqualPolicy7(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1640 mcIdType sz=connI[cell1+1]-connI[cell1];
1641 if(sz==connI[cell2+1]-connI[cell2])
1643 if(conn[connI[cell1]]==conn[connI[cell2]])
1645 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1646 unsigned dim=cm.getDimension();
1651 mcIdType sz1=2*(sz-1);
1652 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1653 mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1654 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1655 work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1660 std::reverse_iterator<mcIdType *> it1((mcIdType *)tmp+sz1);
1661 std::reverse_iterator<mcIdType *> it2((mcIdType *)tmp);
1662 if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1669 {//case of SEG2 and SEG3
1670 if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1672 if(!cm.isQuadratic())
1674 std::reverse_iterator<const mcIdType *> it1(conn+connI[cell1+1]);
1675 std::reverse_iterator<const mcIdType *> it2(conn+connI[cell1]+1);
1676 if(std::equal(it1,it2,conn+connI[cell2]+1))
1682 if(conn[connI[cell1]+1]==conn[connI[cell2]+2] && conn[connI[cell1]+2]==conn[connI[cell2]+1] && conn[connI[cell1]+3]==conn[connI[cell2]+3])
1689 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1697 * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified by \a compType (see zipConnectivityTraducer).
1698 * This method keeps the coordinates of \a this. The comparison starts at rank \a startCellId cell id (included).
1699 * 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.
1700 * If \a startCellId is greater than 0 algorithm starts at cell #startCellId but for each cell all candidates are considered.
1701 * This method is time consuming.
1703 * \param [in] compType input specifying the technique used to compare cells each other.
1704 * - 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.
1705 * - 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)
1706 * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1707 * - 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
1708 * can be used for users not sensitive to orientation of cell
1709 * \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.
1710 * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1711 * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1714 void MEDCouplingUMesh::findCommonCells(int compType, mcIdType startCellId, DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr) const
1716 MCAuto<DataArrayIdType> revNodal=DataArrayIdType::New(),revNodalI=DataArrayIdType::New();
1717 getReverseNodalConnectivity(revNodal,revNodalI);
1718 FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1721 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, mcIdType startCellId, const DataArrayIdType *nodal, const DataArrayIdType *nodalI, const DataArrayIdType *revNodal, const DataArrayIdType *revNodalI,
1722 DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr)
1724 MCAuto<DataArrayIdType> commonCells=DataArrayIdType::New(),commonCellsI=DataArrayIdType::New(); commonCells->alloc(0,1);
1725 mcIdType nbOfCells=nodalI->getNumberOfTuples()-1;
1726 commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1727 const mcIdType *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1728 const mcIdType *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1729 std::vector<bool> isFetched(nbOfCells,false);
1732 for(mcIdType i=startCellId;i<nbOfCells;i++)
1736 const mcIdType *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<mcIdType>(),-1));
1737 std::vector<mcIdType> v,v2;
1738 if(connOfNode!=connPtr+connIPtr[i+1])
1740 const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1741 v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1744 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1748 const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1749 std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1750 v2.resize(std::distance(v2.begin(),it));
1754 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1756 mcIdType pos=commonCellsI->back();
1757 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1758 for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1759 isFetched[*it]=true;
1767 for(mcIdType i=startCellId;i<nbOfCells;i++)
1771 const mcIdType *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<mcIdType>(),-1));
1772 // v2 contains the result of successive intersections using rev nodal on on each node of cell #i
1773 std::vector<mcIdType> v,v2;
1774 if(connOfNode!=connPtr+connIPtr[i+1])
1776 v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1779 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1783 std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1784 v2.resize(std::distance(v2.begin(),it));
1786 // v2 contains now candidates. Problem candidates are sorted using id rank.
1791 auto it(std::find(v2.begin(),v2.end(),i));
1792 std::swap(*v2.begin(),*it);
1794 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1796 mcIdType newPos(commonCells->getNumberOfTuples());
1797 mcIdType pos(commonCellsI->back());
1798 std::sort(commonCells->getPointerSilent()+pos,commonCells->getPointerSilent()+newPos);
1799 commonCellsI->pushBackSilent(newPos);
1800 for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1801 isFetched[*it]=true;
1807 commonCellsArr=commonCells.retn();
1808 commonCellsIArr=commonCellsI.retn();
1812 * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1813 * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1814 * than \a this->getNumberOfCells() in the returned array means that there is no
1815 * corresponding cell in \a this mesh.
1816 * It is expected that \a this and \a other meshes share the same node coordinates
1817 * array, if it is not so an exception is thrown.
1818 * \param [in] other - the mesh to compare with.
1819 * \param [in] compType - specifies a cell comparison technique. For meaning of its
1820 * valid values [0,1,2], see zipConnectivityTraducer().
1821 * \param [out] arr - a new instance of DataArrayIdType returning correspondence
1822 * between cells of the two meshes. It contains \a other->getNumberOfCells()
1823 * values. The caller is to delete this array using
1824 * decrRef() as it is no more needed.
1825 * \return bool - \c true if all cells of \a other mesh are present in the \a this
1828 * \if ENABLE_EXAMPLES
1829 * \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1830 * \ref py_mcumesh_areCellsIncludedIn "Here is a Python example".
1832 * \sa checkDeepEquivalOnSameNodesWith()
1833 * \sa checkGeoEquivalWith()
1835 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayIdType *& arr) const
1837 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1838 mcIdType nbOfCells=getNumberOfCells();
1839 static const int possibleCompType[]={0,1,2};
1840 if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1842 std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1843 std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1845 throw INTERP_KERNEL::Exception(oss.str());
1848 if(other->getNumberOfCells()==0)
1850 MCAuto<DataArrayIdType> dftRet(DataArrayIdType::New()); dftRet->alloc(0,1); arr=dftRet.retn(); arr->setName(other->getName());
1853 DataArrayIdType *commonCells(nullptr),*commonCellsI(nullptr);
1854 mesh->findCommonCells(compType,nbOfCells,commonCells,commonCellsI);
1855 MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1856 mcIdType newNbOfCells=-1;
1857 MCAuto<DataArrayIdType> o2n = DataArrayIdType::ConvertIndexArrayToO2N(ToIdType(mesh->getNumberOfCells()),commonCells->begin(),commonCellsI->begin(),commonCellsI->end(),newNbOfCells);
1858 MCAuto<DataArrayIdType> p0(o2n->selectByTupleIdSafeSlice(0,nbOfCells,1));
1859 mcIdType maxPart(p0->getMaxValueInArray());
1860 bool ret(maxPart==newNbOfCells-1);
1861 MCAuto<DataArrayIdType> p1(p0->invertArrayO2N2N2O(newNbOfCells));
1862 // fill p1 array in case of presence of cells in other not in this
1863 mcIdType *pt(p1->getPointer());
1864 for(mcIdType i = maxPart ; i < newNbOfCells-1 ; ++i )
1867 MCAuto<DataArrayIdType> p2(o2n->subArray(nbOfCells));
1868 p2->transformWithIndArr(p1->begin(),p1->end()); p2->setName(other->getName());
1874 * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1875 * This method tries to determine if \b other is fully included in \b this.
1876 * The main difference is that this method is not expected to throw exception.
1877 * This method has two outputs :
1879 * \param other other mesh
1880 * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1881 * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
1883 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayIdType *& arr) const
1885 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1886 DataArrayIdType *commonCells=0,*commonCellsI=0;
1887 mcIdType thisNbCells=getNumberOfCells();
1888 mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
1889 MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1890 const mcIdType *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
1891 mcIdType otherNbCells=other->getNumberOfCells();
1892 MCAuto<DataArrayIdType> arr2=DataArrayIdType::New();
1893 arr2->alloc(otherNbCells,1);
1894 arr2->fillWithZero();
1895 mcIdType *arr2Ptr=arr2->getPointer();
1896 mcIdType nbOfCommon=commonCellsI->getNumberOfTuples()-1;
1897 for(mcIdType i=0;i<nbOfCommon;i++)
1899 mcIdType start=commonCellsPtr[commonCellsIPtr[i]];
1900 if(start<thisNbCells)
1902 for(mcIdType j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
1904 mcIdType sig=commonCellsPtr[j]>0?1:-1;
1905 mcIdType val=std::abs(commonCellsPtr[j])-1;
1906 if(val>=thisNbCells)
1907 arr2Ptr[val-thisNbCells]=sig*(start+1);
1911 arr2->setName(other->getName());
1912 if(arr2->presenceOfValue(0))
1918 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
1921 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
1922 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
1924 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
1925 std::vector<const MEDCouplingUMesh *> ms(2);
1928 return MergeUMeshesOnSameCoords(ms);
1932 * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
1933 * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
1934 * cellIds is not given explicitly but by a range python like.
1936 * \param start starting ID
1937 * \param end end ID (excluded)
1938 * \param step step size
1939 * \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.
1940 * \return a newly allocated
1942 * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
1943 * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
1945 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, bool keepCoords) const
1947 if(getMeshDimension()!=-1)
1948 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
1951 mcIdType newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
1953 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1955 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1957 return const_cast<MEDCouplingUMesh *>(this);
1962 * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
1963 * The result mesh shares or not the node coordinates array with \a this mesh depending
1964 * on \a keepCoords parameter.
1965 * \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
1966 * to write this mesh to the MED file, its cells must be sorted using
1967 * sortCellsInMEDFileFrmt().
1968 * \param [in] begin - an array of cell ids to include to the new mesh.
1969 * \param [in] end - a pointer to last-plus-one-th element of \a begin.
1970 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
1971 * array of \a this mesh, else "free" nodes are removed from the result mesh
1972 * by calling zipCoords().
1973 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
1974 * to delete this mesh using decrRef() as it is no more needed.
1975 * \throw If the coordinates array is not set.
1976 * \throw If the nodal connectivity of cells is not defined.
1977 * \throw If any cell id in the array \a begin is not valid.
1979 * \if ENABLE_EXAMPLES
1980 * \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
1981 * \ref py_mcumesh_buildPartOfMySelf "Here is a Python example".
1984 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const mcIdType *begin, const mcIdType *end, bool keepCoords) const
1986 if(getMeshDimension()!=-1)
1987 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
1991 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1993 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1995 return const_cast<MEDCouplingUMesh *>(this);
2000 * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
2002 * 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.
2003 * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
2004 * The number of cells of \b this will remain the same with this method.
2006 * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
2007 * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
2008 * \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 ).
2009 * Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
2011 void MEDCouplingUMesh::setPartOfMySelf(const mcIdType *cellIdsBg, const mcIdType *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2013 checkConnectivityFullyDefined();
2014 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2015 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2016 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2017 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2019 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2020 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2021 throw INTERP_KERNEL::Exception(oss.str());
2023 mcIdType nbOfCellsToModify( ToIdType((std::distance(cellIdsBg,cellIdsEnd))));
2024 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2026 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2027 throw INTERP_KERNEL::Exception(oss.str());
2029 mcIdType nbOfCells(getNumberOfCells());
2030 bool easyAssign(true);
2031 const mcIdType *connI(_nodal_connec_index->begin());
2032 const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->begin();
2033 for(const mcIdType *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2035 if(*it>=0 && *it<nbOfCells)
2037 easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2041 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2042 throw INTERP_KERNEL::Exception(oss.str());
2047 DataArrayIdType::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2052 DataArrayIdType *arrOut=0,*arrIOut=0;
2053 DataArrayIdType::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2055 MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2056 setConnectivity(arrOut,arrIOut,true);
2060 void MEDCouplingUMesh::setPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2062 checkConnectivityFullyDefined();
2063 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2064 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2065 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2066 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2068 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2069 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2070 throw INTERP_KERNEL::Exception(oss.str());
2072 mcIdType nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2073 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2075 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2076 throw INTERP_KERNEL::Exception(oss.str());
2078 mcIdType nbOfCells=getNumberOfCells();
2079 bool easyAssign=true;
2080 const mcIdType *connI=_nodal_connec_index->getConstPointer();
2081 const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2083 for(mcIdType i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2085 if(it>=0 && it<nbOfCells)
2087 easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2091 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2092 throw INTERP_KERNEL::Exception(oss.str());
2097 DataArrayIdType::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2102 DataArrayIdType *arrOut=0,*arrIOut=0;
2103 DataArrayIdType::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2105 MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2106 setConnectivity(arrOut,arrIOut,true);
2112 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2113 * this->getMeshDimension(), that bound some cells of \a this mesh.
2114 * The cells of lower dimension to include to the result mesh are selected basing on
2115 * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2116 * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2117 * ==\c false, a cell is copied if any its node is in the array of node ids. The
2118 * created mesh shares the node coordinates array with \a this mesh.
2119 * \param [in] begin - the array of node ids.
2120 * \param [in] end - a pointer to the (last+1)-th element of \a begin.
2121 * \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2122 * array \a begin are added, else cells whose any node is in the
2123 * array \a begin are added.
2124 * \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2125 * to delete this mesh using decrRef() as it is no more needed.
2126 * \throw If the coordinates array is not set.
2127 * \throw If the nodal connectivity of cells is not defined.
2128 * \throw If any node id in \a begin is not valid.
2130 * \if ENABLE_EXAMPLES
2131 * \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2132 * \ref py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2135 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const mcIdType *begin, const mcIdType *end, bool fullyIn) const
2137 MCAuto<DataArrayIdType> desc,descIndx,revDesc,revDescIndx;
2138 desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
2139 MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2140 desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2141 return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2145 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2146 * this->getMeshDimension(), which bound only one cell of \a this mesh.
2147 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2148 * array of \a this mesh, else "free" nodes are removed from the result mesh
2149 * by calling zipCoords().
2150 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2151 * to delete this mesh using decrRef() as it is no more needed.
2152 * \throw If the coordinates array is not set.
2153 * \throw If the nodal connectivity of cells is not defined.
2155 * \if ENABLE_EXAMPLES
2156 * \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2157 * \ref py_mcumesh_buildBoundaryMesh "Here is a Python example".
2160 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2162 DataArrayIdType *desc=DataArrayIdType::New();
2163 DataArrayIdType *descIndx=DataArrayIdType::New();
2164 DataArrayIdType *revDesc=DataArrayIdType::New();
2165 DataArrayIdType *revDescIndx=DataArrayIdType::New();
2167 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2170 descIndx->decrRef();
2171 mcIdType nbOfCells=meshDM1->getNumberOfCells();
2172 const mcIdType *revDescIndxC=revDescIndx->getConstPointer();
2173 std::vector<mcIdType> boundaryCells;
2174 for(mcIdType i=0;i<nbOfCells;i++)
2175 if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2176 boundaryCells.push_back(i);
2177 revDescIndx->decrRef();
2178 MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2183 * This method returns a newly created DataArrayIdType instance containing ids of cells located in boundary.
2184 * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2185 * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2187 DataArrayIdType *MEDCouplingUMesh::findCellIdsOnBoundary() const
2189 checkFullyDefined();
2190 MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2191 MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2192 MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2193 MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2195 buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2196 desc=(DataArrayIdType*)0; descIndx=(DataArrayIdType*)0;
2198 MCAuto<DataArrayIdType> tmp=revDescIndx->deltaShiftIndex();
2199 MCAuto<DataArrayIdType> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayIdType*)0;
2200 const mcIdType *revDescPtr=revDesc->getConstPointer();
2201 const mcIdType *revDescIndxPtr=revDescIndx->getConstPointer();
2202 mcIdType nbOfCells=getNumberOfCells();
2203 std::vector<bool> ret1(nbOfCells,false);
2205 for(const mcIdType *pt=faceIds->begin();pt!=faceIds->end();pt++)
2206 if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2207 { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2209 DataArrayIdType *ret2=DataArrayIdType::New();
2211 mcIdType *ret2Ptr=ret2->getPointer();
2213 for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2216 ret2->setName("BoundaryCells");
2221 * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2222 * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2223 * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2224 * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2226 * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2227 * 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
2228 * equals a cell in \b otherDimM1OnSameCoords.
2230 * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2231 * are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2233 * \param [in] otherDimM1OnSameCoords other mesh
2234 * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2235 * \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
2236 * cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2238 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayIdType *&cellIdsRk0, DataArrayIdType *&cellIdsRk1) const
2240 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2241 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2242 checkConnectivityFullyDefined();
2243 otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2244 if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2245 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2246 MCAuto<DataArrayIdType> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2247 MCAuto<DataArrayIdType> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2248 MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2249 MCAuto<DataArrayIdType> descThisPart=DataArrayIdType::New(),descIThisPart=DataArrayIdType::New(),revDescThisPart=DataArrayIdType::New(),revDescIThisPart=DataArrayIdType::New();
2250 MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2251 const mcIdType *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2252 DataArrayIdType *idsOtherInConsti=0;
2253 bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2254 MCAuto<DataArrayIdType> idsOtherInConstiAuto(idsOtherInConsti);
2256 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2257 std::set<mcIdType> s1;
2258 for(const mcIdType *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2259 s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2260 MCAuto<DataArrayIdType> s1arr_renum1=DataArrayIdType::New(); s1arr_renum1->alloc(s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2261 s1arr_renum1->sort();
2262 cellIdsRk0=s0arr.retn();
2263 //cellIdsRk1=s_renum1.retn();
2264 cellIdsRk1=s1arr_renum1.retn();
2268 * 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
2269 * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2271 * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2273 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2275 MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2276 MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2277 MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2278 MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2280 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2281 revDesc=0; desc=0; descIndx=0;
2282 MCAuto<DataArrayIdType> revDescIndx2=revDescIndx->deltaShiftIndex();
2283 MCAuto<DataArrayIdType> part=revDescIndx2->findIdsEqual(1);
2284 return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2288 * Finds nodes lying on the boundary of \a this mesh.
2289 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of found
2290 * nodes. The caller is to delete this array using decrRef() as it is no
2292 * \throw If the coordinates array is not set.
2293 * \throw If the nodal connectivity of cells is node defined.
2295 * \if ENABLE_EXAMPLES
2296 * \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2297 * \ref py_mcumesh_findBoundaryNodes "Here is a Python example".
2300 DataArrayIdType *MEDCouplingUMesh::findBoundaryNodes() const
2302 MCAuto<MEDCouplingUMesh> skin=computeSkin();
2303 return skin->computeFetchedNodeIds();
2306 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2309 return const_cast<MEDCouplingUMesh *>(this);
2313 * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2314 * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2315 * 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.
2316 * 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.
2317 * 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.
2319 * \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
2320 * parameter is altered during the call.
2321 * \param [out] nodeIdsToDuplicate node ids needed to be duplicated following the algorithm explain above.
2322 * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2323 * \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.
2325 * \warning This method modifies param \b otherDimM1OnSameCoords (for speed reasons).
2327 void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayIdType *& nodeIdsToDuplicate,
2328 DataArrayIdType *& cellIdsNeededToBeRenum, DataArrayIdType *& cellIdsNotModified) const
2330 typedef MCAuto<DataArrayIdType> DAInt;
2331 typedef MCAuto<MEDCouplingUMesh> MCUMesh;
2333 checkFullyDefined();
2334 otherDimM1OnSameCoords.checkFullyDefined();
2335 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2336 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2337 if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2338 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2340 // Checking star-shaped M1 group:
2341 DAInt dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2342 MCUMesh meshM2 = otherDimM1OnSameCoords.buildDescendingConnectivity(dt0, dit0, rdt0, rdit0);
2343 DAInt dsi = rdit0->deltaShiftIndex();
2344 DAInt idsTmp0 = dsi->findIdsNotInRange(-1, 3);
2345 if(idsTmp0->getNumberOfTuples())
2346 throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2347 dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2349 // Get extreme nodes from the group (they won't be duplicated), ie nodes belonging to boundary cells of M1
2350 DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2351 MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2352 DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2353 // Remove from the list points on the boundary of the M0 mesh (those need duplication!)
2354 dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2355 MCUMesh m0desc = buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0;
2356 dsi = rdit0->deltaShiftIndex();
2357 DAInt boundSegs = dsi->findIdsEqual(1); // boundary segs/faces of the M0 mesh
2358 MCUMesh m0descSkin = static_cast<MEDCouplingUMesh *>(m0desc->buildPartOfMySelf(boundSegs->begin(),boundSegs->end(), true));
2359 DAInt fNodes = m0descSkin->computeFetchedNodeIds();
2360 // In 3D, some points on the boundary of M0 still need duplication:
2362 if (getMeshDimension() == 3)
2364 DAInt dnu1=DataArrayIdType::New(), dnu2=DataArrayIdType::New(), dnu3=DataArrayIdType::New(), dnu4=DataArrayIdType::New();
2365 MCUMesh m0descSkinDesc = m0descSkin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4);
2366 dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2367 DataArrayIdType * corresp=0;
2368 meshM2->areCellsIncludedIn(m0descSkinDesc,2,corresp);
2369 DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2371 if (validIds->getNumberOfTuples())
2373 MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0descSkinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2374 DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2375 DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2376 notDup = xtrem->buildSubstraction(fNodes1);
2379 notDup = xtrem->buildSubstraction(fNodes);
2382 notDup = xtrem->buildSubstraction(fNodes);
2384 // Now compute cells around group (i.e. cells where we will do the propagation to identify the two sub-sets delimited by the group)
2385 DAInt m1Nodes = otherDimM1OnSameCoords.computeFetchedNodeIds();
2386 DAInt dupl = m1Nodes->buildSubstraction(notDup);
2387 DAInt cellsAroundGroup = getCellIdsLyingOnNodes(dupl->begin(), dupl->end(), false); // false= take cell in, even if not all nodes are in notDup
2390 MCUMesh m0Part2=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroup->begin(),cellsAroundGroup->end(),true));
2391 mcIdType nCells2 = m0Part2->getNumberOfCells();
2392 DAInt desc00=DataArrayIdType::New(),descI00=DataArrayIdType::New(),revDesc00=DataArrayIdType::New(),revDescI00=DataArrayIdType::New();
2393 MCUMesh m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00);
2395 // Neighbor information of the mesh without considering the crack (serves to count how many connex pieces it is made of)
2396 DataArrayIdType *tmp00=0,*tmp11=0;
2397 MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00, tmp00, tmp11);
2398 DAInt neighInit00(tmp00);
2399 DAInt neighIInit00(tmp11);
2400 // Neighbor information of the mesh WITH the crack (some neighbors are removed):
2401 DataArrayIdType *idsTmp=0;
2402 m01->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsTmp);
2404 // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2405 // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2406 DataArrayIdType::RemoveIdsFromIndexedArrays(ids->begin(),ids->end(),desc00,descI00);
2407 DataArrayIdType *tmp0=0,*tmp1=0;
2408 // Compute the neighbor of each cell in m0Part2, taking into account the broken link above. Two
2409 // cells on either side of the crack (defined by the mesh of low dimension) are not neighbor anymore.
2410 ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00,tmp0,tmp1);
2411 DAInt neigh00(tmp0);
2412 DAInt neighI00(tmp1);
2414 // For each initial connex part of the sub-mesh (or said differently for each independent crack):
2415 mcIdType seed = 0, nIter = 0;
2416 mcIdType nIterMax = nCells2+1; // Safety net for the loop
2417 DAInt hitCells = DataArrayIdType::New(); hitCells->alloc(nCells2);
2418 hitCells->fillWithValue(-1);
2419 DAInt cellsToModifyConn0_torenum = DataArrayIdType::New();
2420 cellsToModifyConn0_torenum->alloc(0,1);
2421 while (nIter < nIterMax)
2423 DAInt t = hitCells->findIdsEqual(-1);
2424 if (!t->getNumberOfTuples())
2426 // Connex zone without the crack (to compute the next seed really)
2428 DAInt connexCheck = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neighInit00,neighIInit00, -1, dnu);
2430 for (mcIdType * ptr = connexCheck->getPointer(); cnt < connexCheck->getNumberOfTuples(); ptr++, cnt++)
2431 hitCells->setIJ(*ptr,0,1);
2432 // Connex zone WITH the crack (to identify cells lying on either part of the crack)
2433 DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neigh00,neighI00, -1, dnu);
2434 cellsToModifyConn0_torenum = DataArrayIdType::Aggregate(cellsToModifyConn0_torenum, spreadZone, 0);
2435 // Compute next seed, i.e. a cell in another connex part, which was not covered by the previous iterations
2436 DAInt comple = cellsToModifyConn0_torenum->buildComplement(nCells2);
2437 DAInt nonHitCells = hitCells->findIdsEqual(-1);
2438 DAInt intersec = nonHitCells->buildIntersection(comple);
2439 if (intersec->getNumberOfTuples())
2440 { seed = intersec->getIJ(0,0); }
2445 if (nIter >= nIterMax)
2446 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate(): internal error - too many iterations.");
2448 DAInt cellsToModifyConn1_torenum=cellsToModifyConn0_torenum->buildComplement(neighI00->getNumberOfTuples()-1);
2449 cellsToModifyConn0_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2450 cellsToModifyConn1_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2452 cellIdsNeededToBeRenum=cellsToModifyConn0_torenum.retn();
2453 cellIdsNotModified=cellsToModifyConn1_torenum.retn();
2454 nodeIdsToDuplicate=dupl.retn();
2458 * This method operates a modification of the connectivity and coords in \b this.
2459 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2460 * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2461 * 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
2462 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2463 * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2465 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2467 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2468 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2470 void MEDCouplingUMesh::duplicateNodes(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd)
2472 mcIdType nbOfNodes=getNumberOfNodes();
2473 duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2474 duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2478 * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2479 * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2481 * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2483 * \sa renumberNodesInConn
2485 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(mcIdType offset)
2487 checkConnectivityFullyDefined();
2488 mcIdType *conn(getNodalConnectivity()->getPointer());
2489 const mcIdType *connIndex(getNodalConnectivityIndex()->getConstPointer());
2490 mcIdType nbOfCells=getNumberOfCells();
2491 for(mcIdType i=0;i<nbOfCells;i++)
2492 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2494 mcIdType& node=conn[iconn];
2495 if(node>=0)//avoid polyhedron separator
2500 _nodal_connec->declareAsNew();
2505 * Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2506 * 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
2509 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<mcIdType,mcIdType>& newNodeNumbersO2N)
2511 this->renumberNodesInConnT< INTERP_KERNEL::HashMap<mcIdType,mcIdType> >(newNodeNumbersO2N);
2515 * Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2516 * 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
2519 void MEDCouplingUMesh::renumberNodesInConn(const std::map<mcIdType,mcIdType>& newNodeNumbersO2N)
2521 this->renumberNodesInConnT< std::map<mcIdType,mcIdType> >(newNodeNumbersO2N);
2525 * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2526 * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2527 * This method is a generalization of shiftNodeNumbersInConn().
2528 * \warning This method performs no check of validity of new ids. **Use it with care !**
2529 * \param [in] newNodeNumbersO2N - a permutation array, of length \a
2530 * this->getNumberOfNodes(), in "Old to New" mode.
2531 * See \ref numbering for more info on renumbering modes.
2532 * \throw If the nodal connectivity of cells is not defined.
2534 * \if ENABLE_EXAMPLES
2535 * \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2536 * \ref py_mcumesh_renumberNodesInConn "Here is a Python example".
2539 void MEDCouplingUMesh::renumberNodesInConn(const mcIdType *newNodeNumbersO2N)
2541 checkConnectivityFullyDefined();
2542 mcIdType *conn=getNodalConnectivity()->getPointer();
2543 const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2544 mcIdType nbOfCells=getNumberOfCells();
2545 for(mcIdType i=0;i<nbOfCells;i++)
2546 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2548 mcIdType& node=conn[iconn];
2549 if(node>=0)//avoid polyhedron separator
2551 node=newNodeNumbersO2N[node];
2554 _nodal_connec->declareAsNew();
2559 * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2560 * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2561 * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2563 * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2565 void MEDCouplingUMesh::shiftNodeNumbersInConn(mcIdType delta)
2567 checkConnectivityFullyDefined();
2568 mcIdType *conn=getNodalConnectivity()->getPointer();
2569 const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2570 mcIdType nbOfCells=getNumberOfCells();
2571 for(mcIdType i=0;i<nbOfCells;i++)
2572 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2574 mcIdType& node=conn[iconn];
2575 if(node>=0)//avoid polyhedron separator
2580 _nodal_connec->declareAsNew();
2585 * This method operates a modification of the connectivity in \b this.
2586 * 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.
2587 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2588 * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2589 * 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
2590 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2591 * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2593 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2594 * As an another consequense after the call of this method \b this can be transiently non cohrent.
2596 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2597 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2598 * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ).
2600 void MEDCouplingUMesh::duplicateNodesInConn(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd, mcIdType offset)
2602 checkConnectivityFullyDefined();
2603 std::map<mcIdType,mcIdType> m;
2604 mcIdType val=offset;
2605 for(const mcIdType *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2607 mcIdType *conn=getNodalConnectivity()->getPointer();
2608 const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2609 mcIdType nbOfCells=getNumberOfCells();
2610 for(mcIdType i=0;i<nbOfCells;i++)
2611 for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2613 mcIdType& node=conn[iconn];
2614 if(node>=0)//avoid polyhedron separator
2616 std::map<mcIdType,mcIdType>::iterator it=m.find(node);
2625 * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2627 * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2628 * After the call of this method the number of cells remains the same as before.
2630 * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2631 * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2632 * be strictly in [0;this->getNumberOfCells()).
2634 * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2635 * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2636 * should be contained in[0;this->getNumberOfCells()).
2638 * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2639 * \param check whether to check content of old2NewBg
2641 void MEDCouplingUMesh::renumberCells(const mcIdType *old2NewBg, bool check)
2643 checkConnectivityFullyDefined();
2644 mcIdType nbCells=getNumberOfCells();
2645 const mcIdType *array=old2NewBg;
2647 array=DataArrayIdType::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2649 const mcIdType *conn=_nodal_connec->getConstPointer();
2650 const mcIdType *connI=_nodal_connec_index->getConstPointer();
2651 MCAuto<DataArrayIdType> o2n=DataArrayIdType::New(); o2n->useArray(array,false,DeallocType::C_DEALLOC,nbCells,1);
2652 MCAuto<DataArrayIdType> n2o=o2n->invertArrayO2N2N2O(nbCells);
2653 const mcIdType *n2oPtr=n2o->begin();
2654 MCAuto<DataArrayIdType> newConn=DataArrayIdType::New();
2655 newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2656 newConn->copyStringInfoFrom(*_nodal_connec);
2657 MCAuto<DataArrayIdType> newConnI=DataArrayIdType::New();
2658 newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2659 newConnI->copyStringInfoFrom(*_nodal_connec_index);
2661 mcIdType *newC=newConn->getPointer();
2662 mcIdType *newCI=newConnI->getPointer();
2665 for(mcIdType i=0;i<nbCells;i++)
2667 mcIdType pos=n2oPtr[i];
2668 mcIdType nbOfElts=connI[pos+1]-connI[pos];
2669 newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2674 setConnectivity(newConn,newConnI);
2676 free(const_cast<mcIdType *>(array));
2680 * Finds cells whose bounding boxes intersect a given bounding box.
2681 * \param [in] bbox - an array defining the bounding box via coordinates of its
2682 * extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2684 * \param [in] eps - a factor used to increase size of the bounding box of cell
2685 * before comparing it with \a bbox. This factor is multiplied by the maximal
2686 * extent of the bounding box of cell to produce an addition to this bounding box.
2687 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids for found
2688 * cells. The caller is to delete this array using decrRef() as it is no more
2690 * \throw If the coordinates array is not set.
2691 * \throw If the nodal connectivity of cells is not defined.
2693 * \if ENABLE_EXAMPLES
2694 * \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2695 * \ref py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2698 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2700 MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2701 if(getMeshDimension()==-1)
2703 elems->pushBackSilent(0);
2704 return elems.retn();
2706 int dim=getSpaceDimension();
2707 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2708 const mcIdType* conn = getNodalConnectivity()->getConstPointer();
2709 const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2710 const double* coords = getCoords()->getConstPointer();
2711 mcIdType nbOfCells=getNumberOfCells();
2712 for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2714 for (int i=0; i<dim; i++)
2716 elem_bb[i*2]=std::numeric_limits<double>::max();
2717 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2720 for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2722 mcIdType node= conn[inode];
2723 if(node>=0)//avoid polyhedron separator
2725 for (int idim=0; idim<dim; idim++)
2727 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2729 elem_bb[idim*2] = coords[node*dim+idim] ;
2731 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2733 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2738 if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2739 elems->pushBackSilent(ielem);
2741 return elems.retn();
2745 * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2746 * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2747 * added in 'elems' parameter.
2749 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2751 MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2752 if(getMeshDimension()==-1)
2754 elems->pushBackSilent(0);
2755 return elems.retn();
2757 int dim=getSpaceDimension();
2758 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2759 const mcIdType* conn = getNodalConnectivity()->getConstPointer();
2760 const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2761 const double* coords = getCoords()->getConstPointer();
2762 mcIdType nbOfCells=getNumberOfCells();
2763 for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2765 for (int i=0; i<dim; i++)
2767 elem_bb[i*2]=std::numeric_limits<double>::max();
2768 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2771 for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2773 mcIdType node= conn[inode];
2774 if(node>=0)//avoid polyhedron separator
2776 for (int idim=0; idim<dim; idim++)
2778 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2780 elem_bb[idim*2] = coords[node*dim+idim] ;
2782 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2784 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2789 if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
2790 elems->pushBackSilent(ielem);
2792 return elems.retn();
2796 * Returns a type of a cell by its id.
2797 * \param [in] cellId - the id of the cell of interest.
2798 * \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
2799 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2801 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(mcIdType cellId) const
2803 const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2804 if(cellId<_nodal_connec_index->getNbOfElems()-1)
2805 return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2808 std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2809 throw INTERP_KERNEL::Exception(oss.str());
2814 * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2815 * This method does not throw exception if geometric type \a type is not in \a this.
2816 * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2817 * The coordinates array is not considered here.
2819 * \param [in] type the geometric type
2820 * \return cell ids in this having geometric type \a type.
2822 DataArrayIdType *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2825 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
2827 checkConnectivityFullyDefined();
2828 mcIdType nbCells=getNumberOfCells();
2829 int mdim=getMeshDimension();
2830 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
2831 if(mdim!=ToIdType(cm.getDimension()))
2832 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
2833 const mcIdType *ptI=_nodal_connec_index->getConstPointer();
2834 const mcIdType *pt=_nodal_connec->getConstPointer();
2835 for(mcIdType i=0;i<nbCells;i++)
2837 if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
2838 ret->pushBackSilent(i);
2844 * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
2846 mcIdType MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2848 const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2849 mcIdType nbOfCells(getNumberOfCells()),ret(0);
2850 for(mcIdType i=0;i<nbOfCells;i++)
2851 if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
2857 * Returns the nodal connectivity of a given cell.
2858 * The separator of faces within polyhedron connectivity (-1) is not returned, thus
2859 * all returned node ids can be used in getCoordinatesOfNode().
2860 * \param [in] cellId - an id of the cell of interest.
2861 * \param [in,out] conn - a vector where the node ids are appended. It is not
2862 * cleared before the appending.
2863 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2865 void MEDCouplingUMesh::getNodeIdsOfCell(mcIdType cellId, std::vector<mcIdType>& conn) const
2867 const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2868 for(const mcIdType *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
2873 std::string MEDCouplingUMesh::simpleRepr() const
2875 static const char msg0[]="No coordinates specified !";
2876 std::ostringstream ret;
2877 ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
2878 ret << "Description of mesh : \"" << getDescription() << "\"\n";
2880 double tt=getTime(tmpp1,tmpp2);
2881 ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
2882 ret << "Iteration : " << tmpp1 << " Order : " << tmpp2 << "\n";
2884 { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
2886 { ret << " Mesh dimension has not been set or is invalid !"; }
2889 const int spaceDim=getSpaceDimension();
2890 ret << spaceDim << "\nInfo attached on space dimension : ";
2891 for(int i=0;i<spaceDim;i++)
2892 ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
2896 ret << msg0 << "\n";
2897 ret << "Number of nodes : ";
2899 ret << getNumberOfNodes() << "\n";
2901 ret << msg0 << "\n";
2902 ret << "Number of cells : ";
2903 if(_nodal_connec!=0 && _nodal_connec_index!=0)
2904 ret << getNumberOfCells() << "\n";
2906 ret << "No connectivity specified !" << "\n";
2907 ret << "Cell types present : ";
2908 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
2910 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
2911 ret << cm.getRepr() << " ";
2917 std::string MEDCouplingUMesh::advancedRepr() const
2919 std::ostringstream ret;
2920 ret << simpleRepr();
2921 ret << "\nCoordinates array : \n___________________\n\n";
2923 _coords->reprWithoutNameStream(ret);
2925 ret << "No array set !\n";
2926 ret << "\n\nConnectivity arrays : \n_____________________\n\n";
2927 reprConnectivityOfThisLL(ret);
2932 * This method returns a C++ code that is a dump of \a this.
2933 * This method will throw if this is not fully defined.
2935 std::string MEDCouplingUMesh::cppRepr() const
2937 static const char coordsName[]="coords";
2938 static const char connName[]="conn";
2939 static const char connIName[]="connI";
2940 checkFullyDefined();
2941 std::ostringstream ret; ret << "// coordinates" << std::endl;
2942 _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
2943 _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
2944 _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
2945 ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
2946 ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
2947 ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
2948 ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
2952 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
2954 std::ostringstream ret;
2955 reprConnectivityOfThisLL(ret);
2960 * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsibility to deal with.
2961 * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
2962 * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
2965 * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
2966 * 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
2967 * with number of tuples set to 0, if not the array is taken as this in the returned instance.
2969 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(std::size_t spaceDim) const
2971 int mdim=getMeshDimension();
2973 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
2974 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
2975 MCAuto<DataArrayIdType> tmp1,tmp2;
2976 bool needToCpyCT=true;
2979 tmp1=DataArrayIdType::New(); tmp1->alloc(0,1);
2987 if(!_nodal_connec_index)
2989 tmp2=DataArrayIdType::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
2994 tmp2=_nodal_connec_index;
2997 ret->setConnectivity(tmp1,tmp2,false);
3002 MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
3003 ret->setCoords(coords);
3006 ret->setCoords(_coords);
3010 mcIdType MEDCouplingUMesh::getNumberOfNodesInCell(mcIdType cellId) const
3012 const mcIdType *ptI=_nodal_connec_index->getConstPointer();
3013 const mcIdType *pt=_nodal_connec->getConstPointer();
3014 if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
3015 return ptI[cellId+1]-ptI[cellId]-1;
3017 return ToIdType(std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind2nd(std::not_equal_to<mcIdType>(),-1)));
3021 * Returns types of cells of the specified part of \a this mesh.
3022 * This method avoids computing sub-mesh explicitly to get its types.
3023 * \param [in] begin - an array of cell ids of interest.
3024 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3025 * \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3026 * describing the cell types.
3027 * \throw If the coordinates array is not set.
3028 * \throw If the nodal connectivity of cells is not defined.
3029 * \sa getAllGeoTypes()
3031 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const mcIdType *begin, const mcIdType *end) const
3033 checkFullyDefined();
3034 std::set<INTERP_KERNEL::NormalizedCellType> ret;
3035 const mcIdType *conn=_nodal_connec->getConstPointer();
3036 const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
3037 for(const mcIdType *w=begin;w!=end;w++)
3038 ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3043 * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3044 * Optionally updates
3045 * a set of types of cells constituting \a this mesh.
3046 * This method is for advanced users having prepared their connectivity before. For
3047 * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3048 * \param [in] conn - the nodal connectivity array.
3049 * \param [in] connIndex - the nodal connectivity index array.
3050 * \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3053 void MEDCouplingUMesh::setConnectivity(DataArrayIdType *conn, DataArrayIdType *connIndex, bool isComputingTypes)
3055 DataArrayIdType::SetArrayIn(conn,_nodal_connec);
3056 DataArrayIdType::SetArrayIn(connIndex,_nodal_connec_index);
3057 if(isComputingTypes)
3063 * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3064 * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3066 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCpy):MEDCouplingPointSet(other,deepCpy),_mesh_dim(other._mesh_dim),
3067 _nodal_connec(0),_nodal_connec_index(0),
3068 _types(other._types)
3070 if(other._nodal_connec)
3071 _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCpy);
3072 if(other._nodal_connec_index)
3073 _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCpy);
3076 MEDCouplingUMesh::~MEDCouplingUMesh()
3079 _nodal_connec->decrRef();
3080 if(_nodal_connec_index)
3081 _nodal_connec_index->decrRef();
3085 * Recomputes a set of cell types of \a this mesh. For more info see
3086 * \ref MEDCouplingUMeshNodalConnectivity.
3088 void MEDCouplingUMesh::computeTypes()
3090 ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3095 * Returns a number of cells constituting \a this mesh.
3096 * \return mcIdType - the number of cells in \a this mesh.
3097 * \throw If the nodal connectivity of cells is not defined.
3099 mcIdType MEDCouplingUMesh::getNumberOfCells() const
3101 if(_nodal_connec_index)
3102 return _nodal_connec_index->getNumberOfTuples()-1;
3107 throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3111 * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3112 * mesh. For more info see \ref meshes.
3113 * \return int - the dimension of \a this mesh.
3114 * \throw If the mesh dimension is not defined using setMeshDimension().
3116 int MEDCouplingUMesh::getMeshDimension() const
3119 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3124 * Returns a length of the nodal connectivity array.
3125 * This method is for test reason. Normally the integer returned is not useable by
3126 * user. For more info see \ref MEDCouplingUMeshNodalConnectivity.
3127 * \return mcIdType - the length of the nodal connectivity array.
3129 mcIdType MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3131 return _nodal_connec->getNbOfElems();
3135 * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3137 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<mcIdType>& tinyInfo, std::vector<std::string>& littleStrings) const
3139 MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3140 tinyInfo.push_back(ToIdType(getMeshDimension()));
3141 tinyInfo.push_back(getNumberOfCells());
3143 tinyInfo.push_back(getNodalConnectivityArrayLen());
3145 tinyInfo.push_back(-1);
3149 * First step of unserialization process.
3151 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<mcIdType>& tinyInfo) const
3153 return tinyInfo[6]<=0;
3157 * Second step of serialization process.
3158 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3159 * \param a1 DataArrayDouble
3160 * \param a2 DataArrayDouble
3161 * \param littleStrings string vector
3163 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<mcIdType>& tinyInfo, DataArrayIdType *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3165 MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3167 a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3171 * Third and final step of serialization process.
3173 void MEDCouplingUMesh::serialize(DataArrayIdType *&a1, DataArrayDouble *&a2) const
3175 MEDCouplingPointSet::serialize(a1,a2);
3176 if(getMeshDimension()>-1)
3178 a1=DataArrayIdType::New();
3179 a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3180 mcIdType *ptA1=a1->getPointer();
3181 const mcIdType *conn=getNodalConnectivity()->getConstPointer();
3182 const mcIdType *index=getNodalConnectivityIndex()->getConstPointer();
3183 ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3184 std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3191 * Second and final unserialization process.
3192 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3194 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<mcIdType>& tinyInfo, const DataArrayIdType *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3196 MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3197 setMeshDimension(FromIdType<int>(tinyInfo[5]));
3201 const mcIdType *recvBuffer=a1->getConstPointer();
3202 MCAuto<DataArrayIdType> myConnecIndex=DataArrayIdType::New();
3203 myConnecIndex->alloc(tinyInfo[6]+1,1);
3204 std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3205 MCAuto<DataArrayIdType> myConnec=DataArrayIdType::New();
3206 myConnec->alloc(tinyInfo[7],1);
3207 std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3208 setConnectivity(myConnec, myConnecIndex);
3215 * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3217 * For 1D cells, the returned field contains lengths.<br>
3218 * For 2D cells, the returned field contains areas.<br>
3219 * For 3D cells, the returned field contains volumes.
3220 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3221 * orientation, i.e. the volume is always positive.
3222 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3223 * and one time . The caller is to delete this field using decrRef() as it is no
3226 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3228 std::string name="MeasureOfMesh_";
3230 mcIdType nbelem=getNumberOfCells();
3231 MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3232 field->setName(name);
3233 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3234 array->alloc(nbelem,1);
3235 double *area_vol=array->getPointer();
3236 field->setArray(array) ; array=0;
3237 field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3238 field->synchronizeTimeWithMesh();
3239 if(getMeshDimension()!=-1)
3242 INTERP_KERNEL::NormalizedCellType type;
3243 int dim_space=getSpaceDimension();
3244 const double *coords=getCoords()->getConstPointer();
3245 const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3246 const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3247 for(mcIdType iel=0;iel<nbelem;iel++)
3249 ipt=connec_index[iel];
3250 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3251 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);
3254 std::transform(area_vol,area_vol+nbelem,area_vol,std::ptr_fun<double,double>(fabs));
3258 area_vol[0]=std::numeric_limits<double>::max();
3260 return field.retn();
3264 * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3266 * For 1D cells, the returned array contains lengths.<br>
3267 * For 2D cells, the returned array contains areas.<br>
3268 * For 3D cells, the returned array contains volumes.
3269 * This method avoids building explicitly a part of \a this mesh to perform the work.
3270 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3271 * orientation, i.e. the volume is always positive.
3272 * \param [in] begin - an array of cell ids of interest.
3273 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3274 * \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3275 * delete this array using decrRef() as it is no more needed.
3277 * \if ENABLE_EXAMPLES
3278 * \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3279 * \ref py_mcumesh_getPartMeasureField "Here is a Python example".
3281 * \sa getMeasureField()
3283 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const mcIdType *begin, const mcIdType *end) const
3285 std::string name="PartMeasureOfMesh_";
3287 std::size_t nbelem=std::distance(begin,end);
3288 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3289 array->setName(name);
3290 array->alloc(nbelem,1);
3291 double *area_vol=array->getPointer();
3292 if(getMeshDimension()!=-1)
3295 INTERP_KERNEL::NormalizedCellType type;
3296 int dim_space=getSpaceDimension();
3297 const double *coords=getCoords()->getConstPointer();
3298 const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3299 const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3300 for(const mcIdType *iel=begin;iel!=end;iel++)
3302 ipt=connec_index[*iel];
3303 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3304 *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3307 std::transform(array->getPointer(),area_vol,array->getPointer(),std::ptr_fun<double,double>(fabs));
3311 area_vol[0]=std::numeric_limits<double>::max();
3313 return array.retn();
3317 * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3318 * \a this one. The returned field contains the dual cell volume for each corresponding
3319 * node in \a this mesh. In other words, the field returns the getMeasureField() of
3320 * the dual mesh in P1 sens of \a this.<br>
3321 * For 1D cells, the returned field contains lengths.<br>
3322 * For 2D cells, the returned field contains areas.<br>
3323 * For 3D cells, the returned field contains volumes.
3324 * This method is useful to check "P1*" conservative interpolators.
3325 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3326 * orientation, i.e. the volume is always positive.
3327 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3328 * nodes and one time. The caller is to delete this array using decrRef() as
3329 * it is no more needed.
3331 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3333 MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3334 std::string name="MeasureOnNodeOfMesh_";
3336 mcIdType nbNodes=getNumberOfNodes();
3337 MCAuto<DataArrayDouble> nnpc;
3339 MCAuto<DataArrayIdType> tmp2(computeNbOfNodesPerCell());
3340 nnpc=tmp2->convertToDblArr();
3342 std::for_each(nnpc->rwBegin(),nnpc->rwEnd(),[](double& v) { v=1./v; });
3343 const double *nnpcPtr(nnpc->begin());
3344 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3345 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3346 array->alloc(nbNodes,1);
3347 double *valsToFill=array->getPointer();
3348 std::fill(valsToFill,valsToFill+nbNodes,0.);
3349 const double *values=tmp->getArray()->getConstPointer();
3350 MCAuto<DataArrayIdType> da=DataArrayIdType::New();
3351 MCAuto<DataArrayIdType> daInd=DataArrayIdType::New();
3352 getReverseNodalConnectivity(da,daInd);
3353 const mcIdType *daPtr=da->getConstPointer();
3354 const mcIdType *daIPtr=daInd->getConstPointer();
3355 for(mcIdType i=0;i<nbNodes;i++)
3356 for(const mcIdType *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3357 valsToFill[i]+=nnpcPtr[*cell]*values[*cell];
3359 ret->setArray(array);
3364 * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3365 * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3366 * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3367 * and are normalized.
3368 * <br> \a this can be either
3369 * - a 2D mesh in 2D or 3D space or
3370 * - an 1D mesh in 2D space.
3372 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3373 * cells and one time. The caller is to delete this field using decrRef() as
3374 * it is no more needed.
3375 * \throw If the nodal connectivity of cells is not defined.
3376 * \throw If the coordinates array is not set.
3377 * \throw If the mesh dimension is not set.
3378 * \throw If the mesh and space dimension is not as specified above.
3380 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3382 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3383 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3384 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3385 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3386 mcIdType nbOfCells=getNumberOfCells();
3387 int nbComp=getMeshDimension()+1;
3388 array->alloc(nbOfCells,nbComp);
3389 double *vals=array->getPointer();
3390 const mcIdType *connI=_nodal_connec_index->getConstPointer();
3391 const mcIdType *conn=_nodal_connec->getConstPointer();
3392 const double *coords=_coords->getConstPointer();
3393 if(getMeshDimension()==2)
3395 if(getSpaceDimension()==3)
3397 MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3398 const double *locPtr=loc->getConstPointer();
3399 for(mcIdType i=0;i<nbOfCells;i++,vals+=3)
3401 mcIdType offset=connI[i];
3402 INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3403 double n=INTERP_KERNEL::norm<3>(vals);
3404 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3409 MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3410 const double *isAbsPtr=isAbs->getArray()->begin();
3411 for(mcIdType i=0;i<nbOfCells;i++,isAbsPtr++)
3412 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3415 else//meshdimension==1
3418 for(mcIdType i=0;i<nbOfCells;i++)
3420 mcIdType offset=connI[i];
3421 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3422 double n=INTERP_KERNEL::norm<2>(tmp);
3423 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3428 ret->setArray(array);
3430 ret->synchronizeTimeWithSupport();
3435 * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3436 * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3437 * and are normalized.
3438 * <br> \a this can be either
3439 * - a 2D mesh in 2D or 3D space or
3440 * - an 1D mesh in 2D space.
3442 * This method avoids building explicitly a part of \a this mesh to perform the work.
3443 * \param [in] begin - an array of cell ids of interest.
3444 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3445 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3446 * cells and one time. The caller is to delete this field using decrRef() as
3447 * it is no more needed.
3448 * \throw If the nodal connectivity of cells is not defined.
3449 * \throw If the coordinates array is not set.
3450 * \throw If the mesh dimension is not set.
3451 * \throw If the mesh and space dimension is not as specified above.
3452 * \sa buildOrthogonalField()
3454 * \if ENABLE_EXAMPLES
3455 * \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3456 * \ref py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3459 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const mcIdType *begin, const mcIdType *end) const
3461 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3462 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3463 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3464 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3465 std::size_t nbelems=std::distance(begin,end);
3466 int nbComp=getMeshDimension()+1;
3467 array->alloc(nbelems,nbComp);
3468 double *vals=array->getPointer();
3469 const mcIdType *connI=_nodal_connec_index->getConstPointer();
3470 const mcIdType *conn=_nodal_connec->getConstPointer();
3471 const double *coords=_coords->getConstPointer();
3472 if(getMeshDimension()==2)
3474 if(getSpaceDimension()==3)
3476 MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3477 const double *locPtr=loc->getConstPointer();
3478 for(const mcIdType *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3480 mcIdType offset=connI[*i];
3481 INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3482 double n=INTERP_KERNEL::norm<3>(vals);
3483 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3488 for(std::size_t i=0;i<nbelems;i++)
3489 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3492 else//meshdimension==1
3495 for(const mcIdType *i=begin;i!=end;i++)
3497 mcIdType offset=connI[*i];
3498 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3499 double n=INTERP_KERNEL::norm<2>(tmp);
3500 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3505 ret->setArray(array);
3507 ret->synchronizeTimeWithSupport();
3512 * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3513 * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3514 * and are \b not normalized.
3515 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3516 * cells and one time. The caller is to delete this field using decrRef() as
3517 * it is no more needed.
3518 * \throw If the nodal connectivity of cells is not defined.
3519 * \throw If the coordinates array is not set.
3520 * \throw If \a this->getMeshDimension() != 1.
3521 * \throw If \a this mesh includes cells of type other than SEG2.
3523 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3525 if(getMeshDimension()!=1)
3526 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3527 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3528 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3529 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3530 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3531 mcIdType nbOfCells=getNumberOfCells();
3532 int spaceDim=getSpaceDimension();
3533 array->alloc(nbOfCells,spaceDim);
3534 double *pt=array->getPointer();
3535 const double *coo=getCoords()->getConstPointer();
3536 std::vector<mcIdType> conn;
3538 for(mcIdType i=0;i<nbOfCells;i++)
3541 getNodeIdsOfCell(i,conn);
3542 pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3544 ret->setArray(array);
3546 ret->synchronizeTimeWithSupport();
3551 * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3552 * returns a new DataArrayIdType, of length equal to the number of 2D cells in the result
3553 * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3554 * from. If a result face is shared by two 3D cells, then the face in included twice in
3556 * \param [in] origin - 3 components of a point defining location of the plane.
3557 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3558 * must be greater than 1e-6.
3559 * \param [in] eps - half-thickness of the plane.
3560 * \param [out] cellIds - a new instance of DataArrayIdType holding ids of 3D cells
3561 * producing correspondent 2D cells. The caller is to delete this array
3562 * using decrRef() as it is no more needed.
3563 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3564 * not share the node coordinates array with \a this mesh. The caller is to
3565 * delete this mesh using decrRef() as it is no more needed.
3566 * \throw If the coordinates array is not set.
3567 * \throw If the nodal connectivity of cells is not defined.
3568 * \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3569 * \throw If magnitude of \a vec is less than 1e-6.
3570 * \throw If the plane does not intersect any 3D cell of \a this mesh.
3571 * \throw If \a this includes quadratic cells.
3573 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3575 checkFullyDefined();
3576 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3577 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3578 MCAuto<DataArrayIdType> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3579 if(candidates->empty())
3580 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3581 std::vector<mcIdType> nodes;
3582 DataArrayIdType *cellIds1D=0;
3583 MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3584 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3585 MCAuto<DataArrayIdType> desc1=DataArrayIdType::New(),desc2=DataArrayIdType::New();
3586 MCAuto<DataArrayIdType> descIndx1=DataArrayIdType::New(),descIndx2=DataArrayIdType::New();
3587 MCAuto<DataArrayIdType> revDesc1=DataArrayIdType::New(),revDesc2=DataArrayIdType::New();
3588 MCAuto<DataArrayIdType> revDescIndx1=DataArrayIdType::New(),revDescIndx2=DataArrayIdType::New();
3589 MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3590 revDesc2=0; revDescIndx2=0;
3591 MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3592 revDesc1=0; revDescIndx1=0;
3593 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3594 MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3596 std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3597 for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3599 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3600 std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3601 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3602 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3603 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3604 MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New());
3605 connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3606 subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3607 if(cellIds2->empty())
3608 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3609 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3610 ret->setCoords(mDesc1->getCoords());
3611 ret->setConnectivity(conn,connI,true);
3612 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3617 * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3618 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
3619 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3621 * \param [in] origin - 3 components of a point defining location of the plane.
3622 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3623 * must be greater than 1e-6.
3624 * \param [in] eps - half-thickness of the plane.
3625 * \param [out] cellIds - a new instance of DataArrayIdType holding ids of faces
3626 * producing correspondent segments. The caller is to delete this array
3627 * using decrRef() as it is no more needed.
3628 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3629 * mesh in 3D space. This mesh does not share the node coordinates array with
3630 * \a this mesh. The caller is to delete this mesh using decrRef() as it is
3632 * \throw If the coordinates array is not set.
3633 * \throw If the nodal connectivity of cells is not defined.
3634 * \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3635 * \throw If magnitude of \a vec is less than 1e-6.
3636 * \throw If the plane does not intersect any 2D cell of \a this mesh.
3637 * \throw If \a this includes quadratic cells.
3639 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3641 checkFullyDefined();
3642 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3643 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3644 MCAuto<DataArrayIdType> candidates(getCellIdsCrossingPlane(origin,vec,eps));
3645 if(candidates->empty())
3646 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3647 std::vector<mcIdType> nodes;
3648 DataArrayIdType *cellIds1D(0);
3649 MCAuto<MEDCouplingUMesh> subMesh(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3650 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3651 MCAuto<DataArrayIdType> desc1(DataArrayIdType::New()),descIndx1(DataArrayIdType::New()),revDesc1(DataArrayIdType::New()),revDescIndx1(DataArrayIdType::New());
3652 MCAuto<MEDCouplingUMesh> mDesc1(subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3653 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3654 MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3656 std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3657 for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3659 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3660 mcIdType ncellsSub=subMesh->getNumberOfCells();
3661 std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(ncellsSub);
3662 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3663 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3664 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3665 MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New()); connI->pushBackSilent(0);
3667 const mcIdType *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3668 const mcIdType *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3669 for(mcIdType i=0;i<ncellsSub;i++)
3671 if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3673 if(cut3DSurf[i].first!=-2)
3675 conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3676 connI->pushBackSilent(conn->getNumberOfTuples());
3677 cellIds2->pushBackSilent(i);
3681 mcIdType cellId3DSurf=cut3DSurf[i].second;
3682 mcIdType offset=nodalI[cellId3DSurf]+1;
3683 mcIdType nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3684 for(mcIdType j=0;j<nbOfEdges;j++)
3686 conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3687 connI->pushBackSilent(conn->getNumberOfTuples());
3688 cellIds2->pushBackSilent(cellId3DSurf);
3693 if(cellIds2->empty())
3694 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3695 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3696 ret->setCoords(mDesc1->getCoords());
3697 ret->setConnectivity(conn,connI,true);
3698 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3702 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::clipSingle3DCellByPlane(const double origin[3], const double vec[3], double eps) const
3704 checkFullyDefined();
3705 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3706 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3707 if(getNumberOfCells()!=1)
3708 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works only on mesh containing exactly one cell !");
3710 std::vector<mcIdType> nodes;
3711 findNodesOnPlane(origin,vec,eps,nodes);
3712 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());
3713 MCAuto<MEDCouplingUMesh> mDesc2(buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2));//meshDim==2 spaceDim==3
3714 revDesc2=0; revDescIndx2=0;
3715 MCAuto<MEDCouplingUMesh> mDesc1(mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3716 revDesc1=0; revDescIndx1=0;
3717 DataArrayIdType *cellIds1D(0);
3718 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3719 MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3720 std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3721 for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3725 mcIdType oldNbNodes(mDesc1->getNumberOfNodes());
3726 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3727 sameNbNodes=(mDesc1->getNumberOfNodes()==oldNbNodes);
3729 std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3730 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->begin(),mDesc2->getNodalConnectivityIndex()->begin(),
3731 mDesc1->getNodalConnectivity()->begin(),mDesc1->getNodalConnectivityIndex()->begin(),
3732 desc1->begin(),descIndx1->begin(),cut3DSurf);
3733 MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New());
3734 connI->pushBackSilent(0); conn->alloc(0,1);
3736 MCAuto<DataArrayIdType> cellIds2(DataArrayIdType::New()); cellIds2->alloc(0,1);
3737 assemblyForSplitFrom3DSurf(cut3DSurf,desc2->begin(),descIndx2->begin(),conn,connI,cellIds2);
3738 if(cellIds2->empty())
3739 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3741 std::vector<std::vector<mcIdType> > res;
3742 buildSubCellsFromCut(cut3DSurf,desc2->begin(),descIndx2->begin(),mDesc1->getCoords()->begin(),eps,res);
3743 std::size_t sz(res.size());
3744 if(ToIdType(res.size())==mDesc1->getNumberOfCells() && sameNbNodes)
3745 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane : cell is not clipped !");
3746 for(std::size_t i=0;i<sz;i++)
3748 conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
3749 conn->insertAtTheEnd(res[i].begin(),res[i].end());
3750 connI->pushBackSilent(conn->getNumberOfTuples());
3752 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
3753 ret->setCoords(mDesc1->getCoords());
3754 ret->setConnectivity(conn,connI,true);
3755 mcIdType nbCellsRet(ret->getNumberOfCells());
3757 MCAuto<DataArrayDouble> vec2(DataArrayDouble::New()); vec2->alloc(1,3); std::copy(vec,vec+3,vec2->getPointer());
3758 MCAuto<MEDCouplingFieldDouble> ortho(ret->buildOrthogonalField());
3759 MCAuto<DataArrayDouble> ortho2(ortho->getArray()->selectByTupleIdSafeSlice(0,1,1));
3760 MCAuto<DataArrayDouble> dott(DataArrayDouble::Dot(ortho2,vec2));
3761 MCAuto<DataArrayDouble> ccm(ret->computeCellCenterOfMass());
3762 MCAuto<DataArrayDouble> occm;
3764 MCAuto<DataArrayDouble> pt(DataArrayDouble::New()); pt->alloc(1,3); std::copy(origin,origin+3,pt->getPointer());
3765 occm=DataArrayDouble::Substract(ccm,pt);
3767 vec2=DataArrayDouble::New(); vec2->alloc(nbCellsRet,3);
3768 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);
3769 MCAuto<DataArrayDouble> dott2(DataArrayDouble::Dot(occm,vec2));
3771 const mcIdType *cPtr(ret->getNodalConnectivity()->begin()),*ciPtr(ret->getNodalConnectivityIndex()->begin());
3772 MCAuto<MEDCouplingUMesh> ret2(MEDCouplingUMesh::New("Clip3D",3));
3773 ret2->setCoords(mDesc1->getCoords());
3774 MCAuto<DataArrayIdType> conn2(DataArrayIdType::New()),conn2I(DataArrayIdType::New());
3775 conn2I->pushBackSilent(0); conn2->alloc(0,1);
3776 std::vector<mcIdType> cell0(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
3777 std::vector<mcIdType> cell1(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
3778 if(dott->getIJ(0,0)>0)
3780 cell0.insert(cell0.end(),cPtr+1,cPtr+ciPtr[1]);
3781 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell1,cell1.end()));
3785 cell1.insert(cell1.end(),cPtr+1,cPtr+ciPtr[1]);
3786 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell0,cell0.end()));
3788 for(mcIdType i=1;i<nbCellsRet;i++)
3790 if(dott2->getIJ(i,0)<0)
3792 if(ciPtr[i+1]-ciPtr[i]>=4)
3794 cell0.push_back(-1);
3795 cell0.insert(cell0.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3800 if(ciPtr[i+1]-ciPtr[i]>=4)
3802 cell1.push_back(-1);
3803 cell1.insert(cell1.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3807 conn2->insertAtTheEnd(cell0.begin(),cell0.end());
3808 conn2I->pushBackSilent(conn2->getNumberOfTuples());
3809 conn2->insertAtTheEnd(cell1.begin(),cell1.end());
3810 conn2I->pushBackSilent(conn2->getNumberOfTuples());
3811 ret2->setConnectivity(conn2,conn2I,true);
3812 ret2->checkConsistencyLight();
3813 ret2->orientCorrectlyPolyhedrons();
3818 * Finds cells whose bounding boxes intersect a given plane.
3819 * \param [in] origin - 3 components of a point defining location of the plane.
3820 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3821 * must be greater than 1e-6.
3822 * \param [in] eps - half-thickness of the plane.
3823 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of the found
3824 * cells. The caller is to delete this array using decrRef() as it is no more
3826 * \throw If the coordinates array is not set.
3827 * \throw If the nodal connectivity of cells is not defined.
3828 * \throw If \a this->getSpaceDimension() != 3.
3829 * \throw If magnitude of \a vec is less than 1e-6.
3830 * \sa buildSlice3D()
3832 DataArrayIdType *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
3834 checkFullyDefined();
3835 if(getSpaceDimension()!=3)
3836 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
3837 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
3839 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
3841 vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
3842 double angle=acos(vec[2]/normm);
3843 MCAuto<DataArrayIdType> cellIds;
3847 MCAuto<DataArrayDouble> coo=_coords->deepCopy();
3848 double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
3849 if(normm2/normm>1e-6)
3850 DataArrayDouble::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer(),coo->getPointer());
3851 MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
3853 mw->getBoundingBox(bbox);
3854 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3855 cellIds=mw->getCellsInBoundingBox(bbox,eps);
3859 getBoundingBox(bbox);
3860 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3861 cellIds=getCellsInBoundingBox(bbox,eps);
3863 return cellIds.retn();
3867 * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
3868 * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
3869 * No consideration of coordinate is done by this method.
3870 * 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)
3871 * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be useful.
3873 bool MEDCouplingUMesh::isContiguous1D() const
3875 if(getMeshDimension()!=1)
3876 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
3877 mcIdType nbCells=getNumberOfCells();
3879 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
3880 const mcIdType *connI(_nodal_connec_index->begin()),*conn(_nodal_connec->begin());
3881 mcIdType ref=conn[connI[0]+2];
3882 for(mcIdType i=1;i<nbCells;i++)
3884 if(conn[connI[i]+1]!=ref)
3886 ref=conn[connI[i]+2];
3892 * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
3893 * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
3894 * \param pt reference point of the line
3895 * \param v normalized director vector of the line
3896 * \param eps max precision before throwing an exception
3897 * \param res output of size this->getNumberOfCells
3899 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
3901 if(getMeshDimension()!=1)
3902 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
3903 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3904 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
3905 if(getSpaceDimension()!=3)
3906 throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
3907 MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
3908 const double *fPtr=f->getArray()->getConstPointer();
3910 for(mcIdType i=0;i<getNumberOfCells();i++)
3912 const double *tmp1=fPtr+3*i;
3913 tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
3914 tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
3915 tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
3916 double n1=INTERP_KERNEL::norm<3>(tmp);
3917 n1/=INTERP_KERNEL::norm<3>(tmp1);
3919 throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
3921 const double *coo=getCoords()->getConstPointer();
3922 for(mcIdType i=0;i<getNumberOfNodes();i++)
3924 std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
3925 std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
3926 res[i]=std::accumulate(tmp,tmp+3,0.);
3931 * 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.
3932 * \a this is expected to be a mesh so that its space dimension is equal to its
3933 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
3934 * 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).
3936 * 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
3937 * 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).
3938 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
3940 * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
3941 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
3943 * \param [in] ptBg the start pointer (included) of the coordinates of the point
3944 * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
3945 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
3946 * \return the positive value of the distance.
3947 * \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
3949 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
3951 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, mcIdType& cellId) const
3953 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
3954 if(meshDim!=spaceDim-1)
3955 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
3956 if(meshDim!=2 && meshDim!=1)
3957 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
3958 checkFullyDefined();
3959 if(ToIdType(std::distance(ptBg,ptEnd))!=spaceDim)
3960 { 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()); }
3961 DataArrayIdType *ret1=0;
3962 MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,DeallocType::C_DEALLOC,1,spaceDim);
3963 MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
3964 MCAuto<DataArrayIdType> ret1Safe(ret1);
3965 cellId=*ret1Safe->begin();
3966 return *ret0->begin();
3970 * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
3971 * to \a this and the first \a cellId in \a this corresponding to the returned distance.
3972 * 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
3973 * 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).
3974 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
3976 * \a this is expected to be a mesh so that its space dimension is equal to its
3977 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
3978 * 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).
3980 * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
3981 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
3983 * \param [in] pts the list of points in which each tuple represents a point
3984 * \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.
3985 * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
3986 * \throw if number of components of \a pts is not equal to the space dimension.
3987 * \throw if mesh dimension of \a this is not equal to space dimension - 1.
3988 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
3990 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayIdType *& cellIds) const
3993 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
3994 pts->checkAllocated();
3995 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
3996 if(meshDim!=spaceDim-1)
3997 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
3998 if(meshDim!=2 && meshDim!=1)
3999 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
4000 if(ToIdType(pts->getNumberOfComponents())!=spaceDim)
4002 std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
4003 throw INTERP_KERNEL::Exception(oss.str());
4005 checkFullyDefined();
4006 mcIdType nbCells=getNumberOfCells();
4008 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
4009 mcIdType nbOfPts=pts->getNumberOfTuples();
4010 MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
4011 MCAuto<DataArrayIdType> ret1=DataArrayIdType::New(); ret1->alloc(nbOfPts,1);
4012 const mcIdType *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
4013 double *ret0Ptr=ret0->getPointer(); mcIdType *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
4014 MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
4015 const double *bbox(bboxArr->begin());
4020 BBTreeDst<3> myTree(bbox,0,0,nbCells);
4021 for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
4023 double x=std::numeric_limits<double>::max();
4024 std::vector<mcIdType> elems;
4025 myTree.getMinDistanceOfMax(ptsPtr,x);
4026 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4027 DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4033 BBTreeDst<2> myTree(bbox,0,0,nbCells);
4034 for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4036 double x=std::numeric_limits<double>::max();
4037 std::vector<mcIdType> elems;
4038 myTree.getMinDistanceOfMax(ptsPtr,x);
4039 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4040 DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4045 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4047 cellIds=ret1.retn();
4056 * Finds cells in contact with a ball (i.e. a point with precision).
4057 * 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.
4058 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4060 * \warning This method is suitable if the caller intends to evaluate only one
4061 * point, for more points getCellsContainingPoints() is recommended as it is
4063 * \param [in] pos - array of coordinates of the ball central point.
4064 * \param [in] eps - ball radius.
4065 * \return mcIdType - a smallest id of cells being in contact with the ball, -1 in case
4066 * if there are no such cells.
4067 * \throw If the coordinates array is not set.
4068 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4070 mcIdType MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4072 std::vector<mcIdType> elts;
4073 getCellsContainingPoint(pos,eps,elts);
4076 return elts.front();
4080 * Finds cells in contact with a ball (i.e. a point with precision).
4081 * 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.
4082 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4083 * \warning This method is suitable if the caller intends to evaluate only one
4084 * point, for more points getCellsContainingPoints() is recommended as it is
4086 * \param [in] pos - array of coordinates of the ball central point.
4087 * \param [in] eps - ball radius.
4088 * \param [out] elts - vector returning ids of the found cells. It is cleared
4089 * before inserting ids.
4090 * \throw If the coordinates array is not set.
4091 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4093 * \if ENABLE_EXAMPLES
4094 * \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4095 * \ref py_mcumesh_getCellsContainingPoint "Here is a Python example".
4098 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<mcIdType>& elts) const
4100 MCAuto<DataArrayIdType> eltsUg,eltsIndexUg;
4101 getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4102 elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4105 void MEDCouplingUMesh::getCellsContainingPointsZeAlg(const double *pos, mcIdType nbOfPoints, double eps,
4106 MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex,
4107 std::function<bool(INTERP_KERNEL::NormalizedCellType,mcIdType)> sensibilityTo2DQuadraticLinearCellsFunc) const
4109 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
4114 const double *coords=_coords->getConstPointer();
4115 getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4118 throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4120 else if(spaceDim==2)
4124 const double *coords=_coords->getConstPointer();
4125 getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4128 throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4130 else if(spaceDim==1)
4134 const double *coords=_coords->getConstPointer();
4135 getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4138 throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4141 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4145 * Finds cells in contact with several balls (i.e. points with precision).
4146 * This method is an extension of getCellContainingPoint() and
4147 * getCellsContainingPoint() for the case of multiple points.
4148 * 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.
4149 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4150 * \param [in] pos - an array of coordinates of points in full interlace mode :
4151 * X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4152 * this->getSpaceDimension() * \a nbOfPoints
4153 * \param [in] nbOfPoints - number of points to locate within \a this mesh.
4154 * \param [in] eps - radius of balls (i.e. the precision).
4155 * \param [out] elts - vector returning ids of found cells.
4156 * \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4157 * dividing cell ids in \a elts into groups each referring to one
4158 * point. Its every element (except the last one) is an index pointing to the
4159 * first id of a group of cells. For example cells in contact with the *i*-th
4160 * point are described by following range of indices:
4161 * [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4162 * \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4163 * Number of cells in contact with the *i*-th point is
4164 * \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4165 * \throw If the coordinates array is not set.
4166 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4168 * \if ENABLE_EXAMPLES
4169 * \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4170 * \ref py_mcumesh_getCellsContainingPoints "Here is a Python example".
4173 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, mcIdType nbOfPoints, double eps,
4174 MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4176 auto yesImSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType ct, int mdim) { return INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic() && mdim == 2; } );
4177 this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,yesImSensibleTo2DQuadraticLinearCellsFunc);
4181 * Behaves like MEDCouplingMesh::getCellsContainingPoints for cells in \a this that are linear.
4182 * For quadratic cells in \a this, this method behaves by just considering linear part of cells.
4183 * This method is here only for backward compatibility (interpolation GaussPoints to GaussPoints).
4185 * \sa MEDCouplingUMesh::getCellsContainingPoints, MEDCouplingRemapper::prepareNotInterpKernelOnlyGaussGauss
4187 void MEDCouplingUMesh::getCellsContainingPointsLinearPartOnlyOnNonDynType(const double *pos, mcIdType nbOfPoints, double eps, MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4189 auto noImNotSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType,mcIdType) { return false; } );
4190 this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,noImNotSensibleTo2DQuadraticLinearCellsFunc);
4194 * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4195 * least two its edges intersect each other anywhere except their extremities. An
4196 * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4197 * \param [in,out] cells - a vector returning ids of the found cells. It is not
4198 * cleared before filling in.
4199 * \param [in] eps - precision.
4200 * \throw If \a this->getMeshDimension() != 2.
4201 * \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4203 void MEDCouplingUMesh::checkButterflyCells(std::vector<mcIdType>& cells, double eps) const
4205 const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4206 if(getMeshDimension()!=2)
4207 throw INTERP_KERNEL::Exception(msg);
4208 int spaceDim=getSpaceDimension();
4209 if(spaceDim!=2 && spaceDim!=3)
4210 throw INTERP_KERNEL::Exception(msg);
4211 const mcIdType *conn=_nodal_connec->getConstPointer();
4212 const mcIdType *connI=_nodal_connec_index->getConstPointer();
4213 mcIdType nbOfCells=getNumberOfCells();
4214 std::vector<double> cell2DinS2;
4215 for(mcIdType i=0;i<nbOfCells;i++)
4217 mcIdType offset=connI[i];
4218 mcIdType nbOfNodesForCell=connI[i+1]-offset-1;
4219 if(nbOfNodesForCell<=3)
4221 bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4222 project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4223 if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4230 * This method is typically requested to unbutterfly 2D linear cells in \b this.
4232 * 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.
4233 * 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.
4235 * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4236 * This convex envelop is computed using Jarvis march algorithm.
4237 * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4238 * 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)
4239 * 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.
4241 * \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.
4242 * \sa MEDCouplingUMesh::colinearize2D
4244 DataArrayIdType *MEDCouplingUMesh::convexEnvelop2D()
4246 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4247 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D works only for meshDim=2 and spaceDim=2 !");
4248 checkFullyDefined();
4249 const double *coords=getCoords()->getConstPointer();
4250 mcIdType nbOfCells=getNumberOfCells();
4251 MCAuto<DataArrayIdType> nodalConnecIndexOut=DataArrayIdType::New();
4252 nodalConnecIndexOut->alloc(nbOfCells+1,1);
4253 MCAuto<DataArrayIdType> nodalConnecOut(DataArrayIdType::New());
4254 mcIdType *workIndexOut=nodalConnecIndexOut->getPointer();
4256 const mcIdType *nodalConnecIn=_nodal_connec->getConstPointer();
4257 const mcIdType *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4258 std::set<INTERP_KERNEL::NormalizedCellType> types;
4259 MCAuto<DataArrayIdType> isChanged(DataArrayIdType::New());
4260 isChanged->alloc(0,1);
4261 for(mcIdType i=0;i<nbOfCells;i++,workIndexOut++)
4263 mcIdType pos=nodalConnecOut->getNumberOfTuples();
4264 if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4265 isChanged->pushBackSilent(i);
4266 types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4267 workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4269 if(isChanged->empty())
4271 setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4273 return isChanged.retn();
4277 * This method is \b NOT const because it can modify \a this.
4278 * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4279 * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4280 * \param policy specifies the type of extrusion chosen:
4281 * - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4282 * will be repeated to build each level
4283 * - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4284 * 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
4285 * 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
4287 * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4289 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4291 checkFullyDefined();
4292 mesh1D->checkFullyDefined();
4293 if(!mesh1D->isContiguous1D())
4294 throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4295 if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4296 throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4297 if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4298 throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4299 if(mesh1D->getMeshDimension()!=1)
4300 throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4302 if(isPresenceOfQuadratic())
4304 if(mesh1D->isFullyQuadratic())
4307 throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4309 mcIdType oldNbOfNodes(getNumberOfNodes());
4310 MCAuto<DataArrayDouble> newCoords;
4315 newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4320 newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4324 throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4326 setCoords(newCoords);
4327 MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4334 * Checks if \a this mesh is constituted by only quadratic cells.
4335 * \return bool - \c true if there are only quadratic cells in \a this mesh.
4336 * \throw If the coordinates array is not set.
4337 * \throw If the nodal connectivity of cells is not defined.
4339 bool MEDCouplingUMesh::isFullyQuadratic() const
4341 checkFullyDefined();
4343 mcIdType nbOfCells=getNumberOfCells();
4344 for(mcIdType i=0;i<nbOfCells && ret;i++)
4346 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4347 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4348 ret=cm.isQuadratic();
4354 * Checks if \a this mesh includes any quadratic cell.
4355 * \return bool - \c true if there is at least one quadratic cells in \a this mesh.
4356 * \throw If the coordinates array is not set.
4357 * \throw If the nodal connectivity of cells is not defined.
4359 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
4361 checkFullyDefined();
4363 mcIdType nbOfCells=getNumberOfCells();
4364 for(mcIdType i=0;i<nbOfCells && !ret;i++)
4366 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4367 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4368 ret=cm.isQuadratic();
4374 * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
4375 * this mesh, it remains unchanged.
4376 * \throw If the coordinates array is not set.
4377 * \throw If the nodal connectivity of cells is not defined.
4379 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
4381 checkFullyDefined();
4382 mcIdType nbOfCells=getNumberOfCells();
4384 const mcIdType *iciptr=_nodal_connec_index->begin();
4385 for(mcIdType i=0;i<nbOfCells;i++)
4387 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4388 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4389 if(cm.isQuadratic())
4391 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4392 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4393 if(!cml.isDynamic())
4394 delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
4396 delta+=(iciptr[i+1]-iciptr[i]-1)/2;
4401 MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New());
4402 const mcIdType *icptr(_nodal_connec->begin());
4403 newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
4404 newConnI->alloc(nbOfCells+1,1);
4405 mcIdType *ocptr(newConn->getPointer()),*ociptr(newConnI->getPointer());
4408 for(mcIdType i=0;i<nbOfCells;i++,ociptr++)
4410 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
4411 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4412 if(!cm.isQuadratic())
4414 _types.insert(type);
4415 ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
4416 ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
4420 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4421 _types.insert(typel);
4422 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4423 mcIdType newNbOfNodes=cml.getNumberOfNodes();
4425 newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
4426 *ocptr++=ToIdType(typel);
4427 ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
4428 ociptr[1]=ociptr[0]+newNbOfNodes+1;
4431 setConnectivity(newConn,newConnI,false);
4435 * This method converts all linear cell in \a this to quadratic one.
4436 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
4437 * 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)
4438 * 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.
4439 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
4440 * end of the existing coordinates.
4442 * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
4443 * corresponding quadratic cells. 1 is those creating the 'most' complex.
4444 * \return a newly created DataArrayIdType instance that the caller should deal with containing cell ids of converted cells.
4446 * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
4448 * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
4450 DataArrayIdType *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
4452 DataArrayIdType *conn=0,*connI=0;
4453 DataArrayDouble *coords=0;
4454 std::set<INTERP_KERNEL::NormalizedCellType> types;
4455 checkFullyDefined();
4456 MCAuto<DataArrayIdType> ret,connSafe,connISafe;
4457 MCAuto<DataArrayDouble> coordsSafe;
4458 int meshDim=getMeshDimension();
4459 switch(conversionType)
4465 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
4466 connSafe=conn; connISafe=connI; coordsSafe=coords;
4469 ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
4470 connSafe=conn; connISafe=connI; coordsSafe=coords;
4473 ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
4474 connSafe=conn; connISafe=connI; coordsSafe=coords;
4477 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
4485 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
4486 connSafe=conn; connISafe=connI; coordsSafe=coords;
4489 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
4490 connSafe=conn; connISafe=connI; coordsSafe=coords;
4493 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
4494 connSafe=conn; connISafe=connI; coordsSafe=coords;
4497 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
4502 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
4504 setConnectivity(connSafe,connISafe,false);
4506 setCoords(coordsSafe);
4511 * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
4512 * so that the number of cells remains the same. Quadratic faces are converted to
4513 * polygons. This method works only for 2D meshes in
4514 * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
4515 * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
4516 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
4517 * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
4518 * a polylinized edge constituting the input polygon.
4519 * \throw If the coordinates array is not set.
4520 * \throw If the nodal connectivity of cells is not defined.
4521 * \throw If \a this->getMeshDimension() != 2.
4522 * \throw If \a this->getSpaceDimension() != 2.
4524 void MEDCouplingUMesh::tessellate2D(double eps)
4526 int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
4528 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
4532 return tessellate2DCurveInternal(eps);
4534 return tessellate2DInternal(eps);
4536 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
4542 * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
4543 * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
4544 * The nodes to be added in those 2D cells are defined by the pair of \a nodeIdsToAdd and \a nodeIdsIndexToAdd.
4545 * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
4546 * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
4547 * This method can be seen as the opposite method of colinearize2D.
4548 * 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
4549 * to avoid to modify the numbering of existing nodes.
4551 * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
4552 * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
4553 * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
4554 * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
4555 * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
4556 * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
4557 * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
4559 * \sa buildDescendingConnectivity2
4561 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayIdType *nodeIdsToAdd, const DataArrayIdType *nodeIdsIndexToAdd, const DataArrayIdType *edgeIdsToBeSplit,
4562 const MEDCouplingUMesh *mesh1Desc, const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *revDesc, const DataArrayIdType *revDescI)
4564 if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
4565 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
4566 nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
4567 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
4568 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
4569 if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
4570 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
4571 //DataArrayIdType *out0(0),*outi0(0);
4572 //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
4573 //MCAuto<DataArrayIdType> out0s(out0),outi0s(outi0);
4574 //out0s=out0s->buildUnique(); out0s->sort(true);
4580 * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
4581 * In addition, returns an array mapping new cells to old ones. <br>
4582 * This method typically increases the number of cells in \a this mesh
4583 * but the number of nodes remains \b unchanged.
4584 * That's why the 3D splitting policies
4585 * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
4586 * \param [in] policy - specifies a pattern used for splitting.
4587 * The semantic of \a policy is:
4588 * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
4589 * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
4590 * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8 into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4591 * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8 into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4594 * \return DataArrayIdType * - a new instance of DataArrayIdType holding, for each new cell,
4595 * an id of old cell producing it. The caller is to delete this array using
4596 * decrRef() as it is no more needed.
4598 * \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
4599 * \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
4600 * and \a this->getMeshDimension() != 3.
4601 * \throw If \a policy is not one of the four discussed above.
4602 * \throw If the nodal connectivity of cells is not defined.
4603 * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
4605 DataArrayIdType *MEDCouplingUMesh::simplexize(int policy)
4610 return simplexizePol0();
4612 return simplexizePol1();
4613 case INTERP_KERNEL::PLANAR_FACE_5:
4614 return simplexizePlanarFace5();
4615 case INTERP_KERNEL::PLANAR_FACE_6:
4616 return simplexizePlanarFace6();
4618 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)");
4623 * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
4624 * - 1D: INTERP_KERNEL::NORM_SEG2
4625 * - 2D: INTERP_KERNEL::NORM_TRI3
4626 * - 3D: INTERP_KERNEL::NORM_TETRA4.
4628 * This method is useful for users that need to use P1 field services as
4629 * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
4630 * All these methods need mesh support containing only simplex cells.
4631 * \return bool - \c true if there are only simplex cells in \a this mesh.
4632 * \throw If the coordinates array is not set.
4633 * \throw If the nodal connectivity of cells is not defined.
4634 * \throw If \a this->getMeshDimension() < 1.
4636 bool MEDCouplingUMesh::areOnlySimplexCells() const
4638 checkFullyDefined();
4639 int mdim=getMeshDimension();
4640 if(mdim<1 || mdim>3)
4641 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
4642 mcIdType nbCells=getNumberOfCells();
4643 const mcIdType *conn=_nodal_connec->begin();
4644 const mcIdType *connI=_nodal_connec_index->begin();
4645 for(mcIdType i=0;i<nbCells;i++)
4647 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4657 * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
4658 * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
4659 * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell.
4660 * Quadratic cells in 2D are also handled. In those cells edges where start=end=midpoint are removed.
4661 * This method does \b not perform geometrical checks and checks only nodal connectivity of cells,
4662 * so it can be useful to call mergeNodes() before calling this method.
4663 * \throw If \a this->getMeshDimension() <= 1.
4664 * \throw If the coordinates array is not set.
4665 * \throw If the nodal connectivity of cells is not defined.
4667 void MEDCouplingUMesh::convertDegeneratedCells()
4669 checkFullyDefined();
4670 if(getMeshDimension()<=1)
4671 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4672 mcIdType nbOfCells=getNumberOfCells();
4675 mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4676 mcIdType *conn=_nodal_connec->getPointer();
4677 mcIdType *index=_nodal_connec_index->getPointer();
4678 mcIdType posOfCurCell=0;
4680 mcIdType lgthOfCurCell;
4681 for(mcIdType i=0;i<nbOfCells;i++)
4683 lgthOfCurCell=index[i+1]-posOfCurCell;
4684 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4686 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4687 conn+newPos+1,newLgth);
4688 conn[newPos]=newType;
4690 posOfCurCell=index[i+1];
4693 if(newPos!=initMeshLgth)
4694 _nodal_connec->reAlloc(newPos);
4699 * Same as MEDCouplingUMesh::convertDegeneratedCells() plus deletion of the flat cells.
4700 * A cell is flat in the following cases:
4701 * - for a linear cell, all points in the connectivity are equal
4702 * - for a quadratic cell, either the above, or a quadratic polygon with two (linear) points and two
4703 * identical quadratic points
4704 * \return a new instance of DataArrayIdType holding ids of removed cells. The caller is to delete
4705 * this array using decrRef() as it is no more needed.
4707 DataArrayIdType *MEDCouplingUMesh::convertDegeneratedCellsAndRemoveFlatOnes()
4709 checkFullyDefined();
4710 if(getMeshDimension()<=1)
4711 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4712 mcIdType nbOfCells=getNumberOfCells();
4713 MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
4716 mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4717 mcIdType *conn=_nodal_connec->getPointer();
4718 mcIdType *index=_nodal_connec_index->getPointer();
4719 mcIdType posOfCurCell=0;
4721 mcIdType lgthOfCurCell, nbDelCells(0);
4722 for(mcIdType i=0;i<nbOfCells;i++)
4724 lgthOfCurCell=index[i+1]-posOfCurCell;
4725 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4727 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4728 conn+newPos+1,newLgth);
4729 // Shall we delete the cell if it is completely degenerated:
4730 bool delCell=INTERP_KERNEL::CellSimplify::isFlatCell(conn, newPos, newLgth, newType);
4734 ret->pushBackSilent(i);
4736 else //if the cell is to be deleted, simply stay at the same place
4738 conn[newPos]=newType;
4741 posOfCurCell=index[i+1];
4742 index[i+1-nbDelCells]=newPos;
4744 if(newPos!=initMeshLgth)
4745 _nodal_connec->reAlloc(newPos);
4746 const mcIdType nCellDel=ret->getNumberOfTuples();
4748 _nodal_connec_index->reAlloc(nbOfCells-nCellDel+1);
4754 * This method remove null 1D cells from \a this. A 1D cell is considered null if start node is equal to end node.
4755 * Only connectivity is considered here.
4757 bool MEDCouplingUMesh::removeDegenerated1DCells()
4759 checkConnectivityFullyDefined();
4760 if(getMeshDimension()!=1)
4761 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::removeDegenerated1DCells works on umeshes with meshdim equals to 1 !");
4762 std::size_t nbCells(getNumberOfCells()),newSize(0),newSize2(0);
4763 const mcIdType *conn(getNodalConnectivity()->begin()),*conni(getNodalConnectivityIndex()->begin());
4765 for(std::size_t i=0;i<nbCells;i++)
4767 INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[conni[i]]);
4768 if(ct==INTERP_KERNEL::NORM_SEG2 || ct==INTERP_KERNEL::NORM_SEG3)
4770 if(conn[conni[i]+1]!=conn[conni[i]+2])
4773 newSize2+=conni[i+1]-conni[i];
4778 std::ostringstream oss; oss << "MEDCouplingUMesh::removeDegenerated1DCells : cell #" << i << " in this is not of type SEG2/SEG3 !";
4779 throw INTERP_KERNEL::Exception(oss.str());
4783 if(newSize==nbCells)//no cells has been removed -> do nothing
4785 MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New()); newConnI->alloc(newSize+1,1); newConn->alloc(newSize2,1);
4786 mcIdType *newConnPtr(newConn->getPointer()),*newConnIPtr(newConnI->getPointer()); newConnIPtr[0]=0;
4787 for(std::size_t i=0;i<nbCells;i++)
4789 if(conn[conni[i]+1]!=conn[conni[i]+2])
4791 newConnIPtr[1]=newConnIPtr[0]+conni[i+1]-conni[i];
4792 newConnPtr=std::copy(conn+conni[i],conn+conni[i+1],newConnPtr);
4796 setConnectivity(newConn,newConnI,true);
4801 * Finds incorrectly oriented cells of this 2D mesh in 3D space.
4802 * A cell is considered to be oriented correctly if an angle between its
4803 * normal vector and a given vector is less than \c PI / \c 2.
4804 * \param [in] vec - 3 components of the vector specifying the correct orientation of
4806 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4808 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4809 * is not cleared before filling in.
4810 * \throw If \a this->getMeshDimension() != 2.
4811 * \throw If \a this->getSpaceDimension() != 3.
4813 * \if ENABLE_EXAMPLES
4814 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4815 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4818 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<mcIdType>& cells) const
4820 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4821 throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
4822 mcIdType nbOfCells=getNumberOfCells();
4823 const mcIdType *conn=_nodal_connec->begin();
4824 const mcIdType *connI=_nodal_connec_index->begin();
4825 const double *coordsPtr=_coords->begin();
4826 for(mcIdType i=0;i<nbOfCells;i++)
4828 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4829 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4831 bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
4832 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4839 * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
4840 * considered to be oriented correctly if an angle between its normal vector and a
4841 * given vector is less than \c PI / \c 2.
4842 * \param [in] vec - 3 components of the vector specifying the correct orientation of
4844 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4846 * \throw If \a this->getMeshDimension() != 2.
4847 * \throw If \a this->getSpaceDimension() != 3.
4849 * \if ENABLE_EXAMPLES
4850 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4851 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4854 * \sa changeOrientationOfCells
4856 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
4858 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4859 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
4860 mcIdType nbOfCells=getNumberOfCells();
4861 mcIdType *conn(_nodal_connec->getPointer());
4862 const mcIdType *connI(_nodal_connec_index->begin());
4863 const double *coordsPtr(_coords->begin());
4864 bool isModified(false);
4865 for(mcIdType i=0;i<nbOfCells;i++)
4867 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4868 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4870 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4871 bool isQuadratic(cm.isQuadratic());
4872 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4875 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4880 _nodal_connec->declareAsNew();
4885 * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
4887 * \sa orientCorrectly2DCells
4889 void MEDCouplingUMesh::changeOrientationOfCells()
4891 int mdim(getMeshDimension());
4892 if(mdim!=2 && mdim!=1)
4893 throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
4894 mcIdType nbOfCells=getNumberOfCells();
4895 mcIdType *conn(_nodal_connec->getPointer());
4896 const mcIdType *connI(_nodal_connec_index->begin());
4899 for(mcIdType i=0;i<nbOfCells;i++)
4901 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4902 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4903 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4908 for(mcIdType i=0;i<nbOfCells;i++)
4910 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4911 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4912 cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4918 * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
4919 * oriented facets. The normal vector of the facet should point out of the cell.
4920 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4921 * is not cleared before filling in.
4922 * \throw If \a this->getMeshDimension() != 3.
4923 * \throw If \a this->getSpaceDimension() != 3.
4924 * \throw If the coordinates array is not set.
4925 * \throw If the nodal connectivity of cells is not defined.
4927 * \if ENABLE_EXAMPLES
4928 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
4929 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
4932 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<mcIdType>& cells) const
4934 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4935 throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
4936 mcIdType nbOfCells=getNumberOfCells();
4937 const mcIdType *conn=_nodal_connec->begin();
4938 const mcIdType *connI=_nodal_connec_index->begin();
4939 const double *coordsPtr=_coords->begin();
4940 for(mcIdType i=0;i<nbOfCells;i++)
4942 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4943 if(type==INTERP_KERNEL::NORM_POLYHED)
4945 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4952 * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
4954 * \throw If \a this->getMeshDimension() != 3.
4955 * \throw If \a this->getSpaceDimension() != 3.
4956 * \throw If the coordinates array is not set.
4957 * \throw If the nodal connectivity of cells is not defined.
4958 * \throw If the reparation fails.
4960 * \if ENABLE_EXAMPLES
4961 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
4962 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
4964 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
4966 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
4968 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4969 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
4970 mcIdType nbOfCells=getNumberOfCells();
4971 mcIdType *conn=_nodal_connec->getPointer();
4972 const mcIdType *connI=_nodal_connec_index->begin();
4973 const double *coordsPtr=_coords->begin();
4974 for(mcIdType i=0;i<nbOfCells;i++)
4976 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4977 if(type==INTERP_KERNEL::NORM_POLYHED)
4981 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4982 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
4984 catch(INTERP_KERNEL::Exception& e)
4986 std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
4987 throw INTERP_KERNEL::Exception(oss.str());
4995 * This method invert orientation of all cells in \a this.
4996 * After calling this method the absolute value of measure of cells in \a this are the same than before calling.
4997 * This method only operates on the connectivity so coordinates are not touched at all.
4999 void MEDCouplingUMesh::invertOrientationOfAllCells()
5001 checkConnectivityFullyDefined();
5002 std::set<INTERP_KERNEL::NormalizedCellType> gts(getAllGeoTypes());
5003 mcIdType *conn(_nodal_connec->getPointer());
5004 const mcIdType *conni(_nodal_connec_index->begin());
5005 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator gt=gts.begin();gt!=gts.end();gt++)
5007 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::OrientationInverter> oi(INTERP_KERNEL::OrientationInverter::BuildInstanceFrom(*gt));
5008 MCAuto<DataArrayIdType> cwt(giveCellsWithType(*gt));
5009 for(const mcIdType *it=cwt->begin();it!=cwt->end();it++)
5010 oi->operate(conn+conni[*it]+1,conn+conni[*it+1]);
5016 * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
5017 * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
5018 * according to which the first facet of the cell should be oriented to have the normal vector
5019 * pointing out of cell.
5020 * \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of fixed
5021 * cells. The caller is to delete this array using decrRef() as it is no more
5023 * \throw If \a this->getMeshDimension() != 3.
5024 * \throw If \a this->getSpaceDimension() != 3.
5025 * \throw If the coordinates array is not set.
5026 * \throw If the nodal connectivity of cells is not defined.
5028 * \if ENABLE_EXAMPLES
5029 * \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
5030 * \ref py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
5032 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5034 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
5036 const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
5037 if(getMeshDimension()!=3)
5038 throw INTERP_KERNEL::Exception(msg);
5039 int spaceDim=getSpaceDimension();
5041 throw INTERP_KERNEL::Exception(msg);
5043 mcIdType nbOfCells=getNumberOfCells();
5044 mcIdType *conn=_nodal_connec->getPointer();
5045 const mcIdType *connI=_nodal_connec_index->begin();
5046 const double *coo=getCoords()->begin();
5047 MCAuto<DataArrayIdType> cells(DataArrayIdType::New()); cells->alloc(0,1);
5048 for(mcIdType i=0;i<nbOfCells;i++)
5050 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5051 if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
5053 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
5055 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5056 cells->pushBackSilent(i);
5060 return cells.retn();
5064 * This method is a faster method to correct orientation of all 3D cells in \a this.
5065 * 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.
5066 * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
5068 * \return a newly allocated mcIdType array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
5069 * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
5071 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
5073 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5074 throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
5075 mcIdType nbOfCells=getNumberOfCells();
5076 mcIdType *conn=_nodal_connec->getPointer();
5077 const mcIdType *connI=_nodal_connec_index->begin();
5078 const double *coordsPtr=_coords->begin();
5079 MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(0,1);
5080 for(mcIdType i=0;i<nbOfCells;i++)
5082 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5085 case INTERP_KERNEL::NORM_TETRA4:
5087 if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5089 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
5090 ret->pushBackSilent(i);
5094 case INTERP_KERNEL::NORM_PYRA5:
5096 if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5098 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
5099 ret->pushBackSilent(i);
5103 case INTERP_KERNEL::NORM_PENTA6:
5104 case INTERP_KERNEL::NORM_HEXA8:
5105 case INTERP_KERNEL::NORM_HEXGP12:
5107 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5109 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5110 ret->pushBackSilent(i);
5114 case INTERP_KERNEL::NORM_POLYHED:
5116 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5118 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5119 ret->pushBackSilent(i);
5124 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 !");
5132 * This method has a sense for meshes with spaceDim==3 and meshDim==2.
5133 * If it is not the case an exception will be thrown.
5134 * This method is fast because the first cell of \a this is used to compute the plane.
5135 * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
5136 * \param pos output of size at least 3 used to store a point owned of searched plane.
5138 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
5140 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5141 throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
5142 const mcIdType *conn=_nodal_connec->begin();
5143 const mcIdType *connI=_nodal_connec_index->begin();
5144 const double *coordsPtr=_coords->begin();
5145 INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
5146 std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
5150 * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
5151 * cells. Currently cells of the following types are treated:
5152 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5153 * For a cell of other type an exception is thrown.
5154 * Space dimension of a 2D mesh can be either 2 or 3.
5155 * The Edge Ratio of a cell \f$t\f$ is:
5156 * \f$\frac{|t|_\infty}{|t|_0}\f$,
5157 * where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
5158 * the smallest edge lengths of \f$t\f$.
5159 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5160 * cells and one time, lying on \a this mesh. The caller is to delete this
5161 * field using decrRef() as it is no more needed.
5162 * \throw If the coordinates array is not set.
5163 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5164 * \throw If the connectivity data array has more than one component.
5165 * \throw If the connectivity data array has a named component.
5166 * \throw If the connectivity index data array has more than one component.
5167 * \throw If the connectivity index data array has a named component.
5168 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
5169 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5170 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5172 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
5174 checkConsistencyLight();
5175 int spaceDim=getSpaceDimension();
5176 int meshDim=getMeshDimension();
5177 if(spaceDim!=2 && spaceDim!=3)
5178 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
5179 if(meshDim!=2 && meshDim!=3)
5180 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
5181 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5183 mcIdType nbOfCells=getNumberOfCells();
5184 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5185 arr->alloc(nbOfCells,1);
5186 double *pt=arr->getPointer();
5187 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5188 const mcIdType *conn=_nodal_connec->begin();
5189 const mcIdType *connI=_nodal_connec_index->begin();
5190 const double *coo=_coords->begin();
5192 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5194 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5197 case INTERP_KERNEL::NORM_TRI3:
5199 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5200 *pt=INTERP_KERNEL::triEdgeRatio(tmp);
5203 case INTERP_KERNEL::NORM_QUAD4:
5205 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5206 *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
5209 case INTERP_KERNEL::NORM_TETRA4:
5211 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5212 *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
5216 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5218 conn+=connI[i+1]-connI[i];
5220 ret->setName("EdgeRatio");
5221 ret->synchronizeTimeWithSupport();
5226 * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
5227 * cells. Currently cells of the following types are treated:
5228 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5229 * For a cell of other type an exception is thrown.
5230 * Space dimension of a 2D mesh can be either 2 or 3.
5231 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5232 * cells and one time, lying on \a this mesh. The caller is to delete this
5233 * field using decrRef() as it is no more needed.
5234 * \throw If the coordinates array is not set.
5235 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5236 * \throw If the connectivity data array has more than one component.
5237 * \throw If the connectivity data array has a named component.
5238 * \throw If the connectivity index data array has more than one component.
5239 * \throw If the connectivity index data array has a named component.
5240 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
5241 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5242 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5244 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
5246 checkConsistencyLight();
5247 int spaceDim=getSpaceDimension();
5248 int meshDim=getMeshDimension();
5249 if(spaceDim!=2 && spaceDim!=3)
5250 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
5251 if(meshDim!=2 && meshDim!=3)
5252 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
5253 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5255 mcIdType nbOfCells=getNumberOfCells();
5256 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5257 arr->alloc(nbOfCells,1);
5258 double *pt=arr->getPointer();
5259 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5260 const mcIdType *conn=_nodal_connec->begin();
5261 const mcIdType *connI=_nodal_connec_index->begin();
5262 const double *coo=_coords->begin();
5264 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5266 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5269 case INTERP_KERNEL::NORM_TRI3:
5271 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5272 *pt=INTERP_KERNEL::triAspectRatio(tmp);
5275 case INTERP_KERNEL::NORM_QUAD4:
5277 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5278 *pt=INTERP_KERNEL::quadAspectRatio(tmp);
5281 case INTERP_KERNEL::NORM_TETRA4:
5283 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5284 *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
5288 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5290 conn+=connI[i+1]-connI[i];
5292 ret->setName("AspectRatio");
5293 ret->synchronizeTimeWithSupport();
5298 * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
5299 * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
5300 * in 3D space. Currently only cells of the following types are
5301 * treated: INTERP_KERNEL::NORM_QUAD4.
5302 * For a cell of other type an exception is thrown.
5303 * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
5305 * \f$t=\vec{da}\times\vec{ab}\f$,
5306 * \f$u=\vec{ab}\times\vec{bc}\f$
5307 * \f$v=\vec{bc}\times\vec{cd}\f$
5308 * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
5310 * W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
5312 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5313 * cells and one time, lying on \a this mesh. The caller is to delete this
5314 * field using decrRef() as it is no more needed.
5315 * \throw If the coordinates array is not set.
5316 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5317 * \throw If the connectivity data array has more than one component.
5318 * \throw If the connectivity data array has a named component.
5319 * \throw If the connectivity index data array has more than one component.
5320 * \throw If the connectivity index data array has a named component.
5321 * \throw If \a this->getMeshDimension() != 2.
5322 * \throw If \a this->getSpaceDimension() != 3.
5323 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5325 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
5327 checkConsistencyLight();
5328 int spaceDim=getSpaceDimension();
5329 int meshDim=getMeshDimension();
5331 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
5333 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
5334 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5336 mcIdType nbOfCells=getNumberOfCells();
5337 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5338 arr->alloc(nbOfCells,1);
5339 double *pt=arr->getPointer();
5340 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5341 const mcIdType *conn=_nodal_connec->begin();
5342 const mcIdType *connI=_nodal_connec_index->begin();
5343 const double *coo=_coords->begin();
5345 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5347 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5350 case INTERP_KERNEL::NORM_QUAD4:
5352 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5353 *pt=INTERP_KERNEL::quadWarp(tmp);
5357 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
5359 conn+=connI[i+1]-connI[i];
5361 ret->setName("Warp");
5362 ret->synchronizeTimeWithSupport();
5368 * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
5369 * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
5370 * treated: INTERP_KERNEL::NORM_QUAD4.
5371 * The skew is computed as follow for a quad with points (a,b,c,d): let
5372 * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
5373 * then the skew is computed as:
5375 * s=\frac{u}{|u|}\cdot\frac{v}{|v|}
5378 * For a cell of other type an exception is thrown.
5379 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5380 * cells and one time, lying on \a this mesh. The caller is to delete this
5381 * field using decrRef() as it is no more needed.
5382 * \throw If the coordinates array is not set.
5383 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5384 * \throw If the connectivity data array has more than one component.
5385 * \throw If the connectivity data array has a named component.
5386 * \throw If the connectivity index data array has more than one component.
5387 * \throw If the connectivity index data array has a named component.
5388 * \throw If \a this->getMeshDimension() != 2.
5389 * \throw If \a this->getSpaceDimension() != 3.
5390 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
5392 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
5394 checkConsistencyLight();
5395 int spaceDim=getSpaceDimension();
5396 int meshDim=getMeshDimension();
5398 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
5400 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
5401 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5403 mcIdType nbOfCells=getNumberOfCells();
5404 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5405 arr->alloc(nbOfCells,1);
5406 double *pt=arr->getPointer();
5407 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5408 const mcIdType *conn=_nodal_connec->begin();
5409 const mcIdType *connI=_nodal_connec_index->begin();
5410 const double *coo=_coords->begin();
5412 for(mcIdType i=0;i<nbOfCells;i++,pt++)
5414 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5417 case INTERP_KERNEL::NORM_QUAD4:
5419 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5420 *pt=INTERP_KERNEL::quadSkew(tmp);
5424 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
5426 conn+=connI[i+1]-connI[i];
5428 ret->setName("Skew");
5429 ret->synchronizeTimeWithSupport();
5434 * 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.
5436 * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
5438 * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
5440 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
5442 checkConsistencyLight();
5443 MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
5445 std::set<INTERP_KERNEL::NormalizedCellType> types;
5446 ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
5447 int spaceDim(getSpaceDimension());
5448 mcIdType nbCells(getNumberOfCells());
5449 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
5450 arr->alloc(nbCells,1);
5451 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
5453 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
5454 MCAuto<DataArrayIdType> cellIds(giveCellsWithType(*it));
5455 dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
5458 ret->setName("Diameter");
5463 * This method aggregate the bbox of each cell and put it into bbox parameter (xmin,xmax,ymin,ymax,zmin,zmax).
5465 * \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)
5466 * For all other cases this input parameter is ignored.
5467 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5469 * \throw If \a this is not fully set (coordinates and connectivity).
5470 * \throw If a cell in \a this has no valid nodeId.
5471 * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5473 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
5475 int mDim(getMeshDimension()),sDim(getSpaceDimension());
5476 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.
5477 return getBoundingBoxForBBTreeFast();
5478 if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
5480 bool presenceOfQuadratic(false);
5481 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
5483 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
5484 if(cm.isQuadratic())
5485 presenceOfQuadratic=true;
5487 if(!presenceOfQuadratic)
5488 return getBoundingBoxForBBTreeFast();
5489 if(mDim==2 && sDim==2)
5490 return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
5492 return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
5494 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) !");
5498 * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
5499 * So meshes having quadratic cells the computed bounding boxes can be invalid !
5501 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5503 * \throw If \a this is not fully set (coordinates and connectivity).
5504 * \throw If a cell in \a this has no valid nodeId.
5506 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
5508 checkFullyDefined();
5509 int spaceDim(getSpaceDimension());
5510 mcIdType nbOfCells(getNumberOfCells()), nbOfNodes(getNumberOfNodes());
5511 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5512 double *bbox(ret->getPointer());
5513 for(mcIdType i=0;i<nbOfCells*spaceDim;i++)
5515 bbox[2*i]=std::numeric_limits<double>::max();
5516 bbox[2*i+1]=-std::numeric_limits<double>::max();
5518 const double *coordsPtr(_coords->begin());
5519 const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5520 for(mcIdType i=0;i<nbOfCells;i++)
5522 mcIdType offset=connI[i]+1;
5523 mcIdType nbOfNodesForCell(connI[i+1]-offset),kk(0);
5524 for(mcIdType j=0;j<nbOfNodesForCell;j++)
5526 mcIdType nodeId=conn[offset+j];
5527 if(nodeId>=0 && nodeId<nbOfNodes)
5529 for(int k=0;k<spaceDim;k++)
5531 bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
5532 bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
5539 std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
5540 throw INTERP_KERNEL::Exception(oss.str());
5547 * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
5548 * useful for 2D meshes having quadratic cells
5549 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5550 * the two extremities of the arc of circle).
5552 * \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)
5553 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5554 * \throw If \a this is not fully defined.
5555 * \throw If \a this is not a mesh with meshDimension equal to 2.
5556 * \throw If \a this is not a mesh with spaceDimension equal to 2.
5557 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
5559 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
5561 checkFullyDefined();
5562 INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5564 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5565 mcIdType nbOfCells=getNumberOfCells();
5566 if(spaceDim!=2 || mDim!=2)
5567 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!");
5568 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5569 double *bbox(ret->getPointer());
5570 const double *coords(_coords->begin());
5571 const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5572 for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5574 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5575 mcIdType sz(connI[1]-connI[0]-1);
5576 std::vector<INTERP_KERNEL::Node *> nodes(sz);
5577 INTERP_KERNEL::QuadraticPolygon *pol(0);
5578 for(mcIdType j=0;j<sz;j++)
5580 mcIdType nodeId(conn[*connI+1+j]);
5581 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5583 if(!cm.isQuadratic())
5584 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
5586 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
5587 INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
5588 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
5594 * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
5595 * useful for 2D meshes having quadratic cells
5596 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5597 * the two extremities of the arc of circle).
5599 * \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)
5600 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5601 * \throw If \a this is not fully defined.
5602 * \throw If \a this is not a mesh with meshDimension equal to 1.
5603 * \throw If \a this is not a mesh with spaceDimension equal to 2.
5604 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5606 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
5608 checkFullyDefined();
5609 int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5610 mcIdType nbOfCells=getNumberOfCells();
5611 if(spaceDim!=2 || mDim!=1)
5612 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!");
5613 INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5614 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5615 double *bbox(ret->getPointer());
5616 const double *coords(_coords->begin());
5617 const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5618 for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5620 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5621 mcIdType sz(connI[1]-connI[0]-1);
5622 std::vector<INTERP_KERNEL::Node *> nodes(sz);
5623 INTERP_KERNEL::Edge *edge(0);
5624 for(mcIdType j=0;j<sz;j++)
5626 mcIdType nodeId(conn[*connI+1+j]);
5627 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5629 if(!cm.isQuadratic())
5630 edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
5632 edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
5633 const INTERP_KERNEL::Bounds& b(edge->getBounds());
5634 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
5641 namespace MEDCouplingImpl
5646 ConnReader(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5647 bool operator() (const mcIdType& pos) { return _conn[pos]!=_val; }
5649 const mcIdType *_conn;
5656 ConnReader2(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5657 bool operator() (const mcIdType& pos) { return _conn[pos]==_val; }
5659 const mcIdType *_conn;
5667 * This method expects that \a this is sorted by types. If not an exception will be thrown.
5668 * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
5669 * \a this is composed in cell types.
5670 * The returned array is of size 3*n where n is the number of different types present in \a this.
5671 * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
5672 * This parameter is kept only for compatibility with other method listed above.
5674 std::vector<mcIdType> MEDCouplingUMesh::getDistributionOfTypes() const
5676 checkConnectivityFullyDefined();
5677 const mcIdType *conn=_nodal_connec->begin();
5678 const mcIdType *connI=_nodal_connec_index->begin();
5679 const mcIdType *work=connI;
5680 mcIdType nbOfCells=getNumberOfCells();
5681 std::size_t n=getAllGeoTypes().size();
5682 std::vector<mcIdType> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
5683 std::set<INTERP_KERNEL::NormalizedCellType> types;
5684 for(std::size_t i=0;work!=connI+nbOfCells;i++)
5686 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
5687 if(types.find(typ)!=types.end())
5689 std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
5690 oss << " is not contiguous !";
5691 throw INTERP_KERNEL::Exception(oss.str());
5695 const mcIdType *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
5696 ret[3*i+1]=ToIdType(std::distance(work,work2));
5703 * This method is used to check that this has contiguous cell type in same order than described in \a code.
5704 * only for types cell, type node is not managed.
5705 * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
5706 * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
5707 * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
5708 * If 2 or more same geometric type is in \a code and exception is thrown too.
5710 * This method firstly checks
5711 * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
5712 * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
5713 * an exception is thrown too.
5715 * If all geometric types in \a code are exactly those in \a this null pointer is returned.
5716 * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
5717 * and a DataArrayIdType instance is returned that the user has the responsibility to deallocate.
5719 DataArrayIdType *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<mcIdType>& code, const std::vector<const DataArrayIdType *>& idsPerType) const
5722 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
5723 std::size_t sz=code.size();
5726 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
5727 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5729 bool isNoPflUsed=true;
5730 for(std::size_t i=0;i<n;i++)
5731 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
5733 types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
5735 if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
5736 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
5737 isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
5740 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
5743 if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
5744 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
5745 if(types.size()==_types.size())
5748 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
5750 mcIdType *retPtr=ret->getPointer();
5751 const mcIdType *connI=_nodal_connec_index->begin();
5752 const mcIdType *conn=_nodal_connec->begin();
5753 mcIdType nbOfCells=getNumberOfCells();
5754 const mcIdType *i=connI;
5756 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
5758 i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,ToIdType((*it))));
5759 mcIdType offset=ToIdType(std::distance(connI,i));
5760 const mcIdType *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType((*it))));
5761 mcIdType nbOfCellsOfCurType=ToIdType(std::distance(i,j));
5762 if(code[3*kk+2]==-1)
5763 for(mcIdType k=0;k<nbOfCellsOfCurType;k++)
5767 mcIdType idInIdsPerType=code[3*kk+2];
5768 if(idInIdsPerType>=0 && idInIdsPerType<ToIdType(idsPerType.size()))
5770 const DataArrayIdType *zePfl=idsPerType[idInIdsPerType];
5773 zePfl->checkAllocated();
5774 if(zePfl->getNumberOfComponents()==1)
5776 for(const mcIdType *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
5778 if(*k>=0 && *k<nbOfCellsOfCurType)
5779 *retPtr=(*k)+offset;
5782 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
5783 oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
5784 throw INTERP_KERNEL::Exception(oss.str());
5789 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
5792 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
5796 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
5797 oss << " should be in [0," << idsPerType.size() << ") !";
5798 throw INTERP_KERNEL::Exception(oss.str());
5807 * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
5808 * 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.
5809 * 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.
5810 * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
5812 * \param [in] profile list of IDs constituing the profile
5813 * \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.
5814 * \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,
5815 * \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
5816 * \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.
5817 * This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
5818 * \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
5820 void MEDCouplingUMesh::splitProfilePerType(const DataArrayIdType *profile, std::vector<mcIdType>& code, std::vector<DataArrayIdType *>& idsInPflPerType, std::vector<DataArrayIdType *>& idsPerType, bool smartPflKiller) const
5823 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
5824 if(profile->getNumberOfComponents()!=1)
5825 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
5826 checkConnectivityFullyDefined();
5827 const mcIdType *conn=_nodal_connec->begin();
5828 const mcIdType *connI=_nodal_connec_index->begin();
5829 mcIdType nbOfCells=getNumberOfCells();
5830 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5831 std::vector<mcIdType> typeRangeVals(1);
5832 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
5834 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5835 if(std::find(types.begin(),types.end(),curType)!=types.end())
5837 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
5839 types.push_back(curType);
5840 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
5841 typeRangeVals.push_back(ToIdType(std::distance(connI,i)));
5844 DataArrayIdType *castArr=0,*rankInsideCast=0,*castsPresent=0;
5845 profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
5846 MCAuto<DataArrayIdType> tmp0=castArr;
5847 MCAuto<DataArrayIdType> tmp1=rankInsideCast;
5848 MCAuto<DataArrayIdType> tmp2=castsPresent;
5850 mcIdType nbOfCastsFinal=castsPresent->getNumberOfTuples();
5851 code.resize(3*nbOfCastsFinal);
5852 std::vector< MCAuto<DataArrayIdType> > idsInPflPerType2;
5853 std::vector< MCAuto<DataArrayIdType> > idsPerType2;
5854 for(mcIdType i=0;i<nbOfCastsFinal;i++)
5856 mcIdType castId=castsPresent->getIJ(i,0);
5857 MCAuto<DataArrayIdType> tmp3=castArr->findIdsEqual(castId);
5858 idsInPflPerType2.push_back(tmp3);
5859 code[3*i]=ToIdType(types[castId]);
5860 code[3*i+1]=tmp3->getNumberOfTuples();
5861 MCAuto<DataArrayIdType> tmp4=rankInsideCast->selectByTupleId(tmp3->begin(),tmp3->begin()+tmp3->getNumberOfTuples());
5862 if(!smartPflKiller || !tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
5864 tmp4->copyStringInfoFrom(*profile);
5865 idsPerType2.push_back(tmp4);
5866 code[3*i+2]=ToIdType(idsPerType2.size())-1;
5873 std::size_t sz2=idsInPflPerType2.size();
5874 idsInPflPerType.resize(sz2);
5875 for(std::size_t i=0;i<sz2;i++)
5877 DataArrayIdType *locDa=idsInPflPerType2[i];
5879 idsInPflPerType[i]=locDa;
5881 std::size_t sz=idsPerType2.size();
5882 idsPerType.resize(sz);
5883 for(std::size_t i=0;i<sz;i++)
5885 DataArrayIdType *locDa=idsPerType2[i];
5887 idsPerType[i]=locDa;
5892 * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
5893 * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
5894 * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
5895 * 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.
5897 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *&revDesc, DataArrayIdType *&revDescIndx, DataArrayIdType *& nM1LevMeshIds, DataArrayIdType *&meshnM1Old2New) const
5899 checkFullyDefined();
5900 nM1LevMesh->checkFullyDefined();
5901 if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
5902 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
5903 if(_coords!=nM1LevMesh->getCoords())
5904 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
5905 MCAuto<DataArrayIdType> tmp0=DataArrayIdType::New();
5906 MCAuto<DataArrayIdType> tmp1=DataArrayIdType::New();
5907 MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
5908 MCAuto<DataArrayIdType> ret0=ret1->sortCellsInMEDFileFrmt();
5909 desc->transformWithIndArr(ret0->begin(),ret0->begin()+ret0->getNbOfElems());
5910 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
5911 tmp->setConnectivity(tmp0,tmp1);
5912 tmp->renumberCells(ret0->begin(),false);
5913 revDesc=tmp->getNodalConnectivity();
5914 revDescIndx=tmp->getNodalConnectivityIndex();
5915 DataArrayIdType *ret=0;
5916 if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
5919 ret->getMaxValue(tmp2);
5921 std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
5922 throw INTERP_KERNEL::Exception(oss.str());
5927 revDescIndx->incrRef();
5930 meshnM1Old2New=ret0;
5935 * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
5936 * necessary for writing the mesh to MED file. Additionally returns a permutation array
5937 * in "Old to New" mode.
5938 * \return DataArrayIdType * - a new instance of DataArrayIdType. The caller is to delete
5939 * this array using decrRef() as it is no more needed.
5940 * \throw If the nodal connectivity of cells is not defined.
5942 DataArrayIdType *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
5944 checkConnectivityFullyDefined();
5945 MCAuto<DataArrayIdType> ret=getRenumArrForMEDFileFrmt();
5946 renumberCells(ret->begin(),false);
5951 * This methods checks that cells are sorted by their types.
5952 * This method makes asumption (no check) that connectivity is correctly set before calling.
5954 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
5956 checkFullyDefined();
5957 const mcIdType *conn=_nodal_connec->begin();
5958 const mcIdType *connI=_nodal_connec_index->begin();
5959 mcIdType nbOfCells=getNumberOfCells();
5960 std::set<INTERP_KERNEL::NormalizedCellType> types;
5961 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
5963 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5964 if(types.find(curType)!=types.end())
5966 types.insert(curType);
5967 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
5973 * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
5974 * The geometric type order is specified by MED file.
5976 * \sa MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
5978 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
5980 return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
5984 * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
5985 * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
5986 * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
5987 * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
5989 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
5991 checkFullyDefined();
5992 const mcIdType *conn=_nodal_connec->begin();
5993 const mcIdType *connI=_nodal_connec_index->begin();
5994 mcIdType nbOfCells=getNumberOfCells();
5997 mcIdType lastPos=-1;
5998 std::set<INTERP_KERNEL::NormalizedCellType> sg;
5999 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6001 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6002 const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
6003 if(isTypeExists!=orderEnd)
6005 mcIdType pos=ToIdType(std::distance(orderBg,isTypeExists));
6009 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6013 if(sg.find(curType)==sg.end())
6015 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6026 * This method returns 2 newly allocated DataArrayIdType instances. The first is an array of size 'this->getNumberOfCells()' with one component,
6027 * 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
6028 * 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'.
6030 DataArrayIdType *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayIdType *&nbPerType) const
6032 checkConnectivityFullyDefined();
6033 mcIdType nbOfCells=getNumberOfCells();
6034 const mcIdType *conn=_nodal_connec->begin();
6035 const mcIdType *connI=_nodal_connec_index->begin();
6036 MCAuto<DataArrayIdType> tmpa=DataArrayIdType::New();
6037 MCAuto<DataArrayIdType> tmpb=DataArrayIdType::New();
6038 tmpa->alloc(nbOfCells,1);
6039 tmpb->alloc(std::distance(orderBg,orderEnd),1);
6040 tmpb->fillWithZero();
6041 mcIdType *tmp=tmpa->getPointer();
6042 mcIdType *tmp2=tmpb->getPointer();
6043 for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6045 const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
6048 mcIdType pos=ToIdType(std::distance(orderBg,where));
6050 tmp[std::distance(connI,i)]=pos;
6054 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
6055 std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
6056 oss << " has a type " << cm.getRepr() << " not in input array of type !";
6057 throw INTERP_KERNEL::Exception(oss.str());
6060 nbPerType=tmpb.retn();
6065 * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
6067 * \return a new object containing the old to new correspondence.
6069 * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6071 DataArrayIdType *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
6073 return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6077 * 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.
6078 * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
6079 * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
6080 * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
6082 DataArrayIdType *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6084 DataArrayIdType *nbPerType=0;
6085 MCAuto<DataArrayIdType> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
6086 nbPerType->decrRef();
6087 return tmpa->buildPermArrPerLevel();
6091 * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
6092 * The number of cells remains unchanged after the call of this method.
6093 * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
6094 * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6096 * \return the array giving the correspondence old to new.
6098 DataArrayIdType *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
6100 checkFullyDefined();
6102 const mcIdType *conn=_nodal_connec->begin();
6103 const mcIdType *connI=_nodal_connec_index->begin();
6104 mcIdType nbOfCells=getNumberOfCells();
6105 std::vector<INTERP_KERNEL::NormalizedCellType> types;
6106 for(const mcIdType *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
6107 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
6109 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6110 types.push_back(curType);
6111 for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
6113 DataArrayIdType *ret=DataArrayIdType::New();
6114 ret->alloc(nbOfCells,1);
6115 mcIdType *retPtr=ret->getPointer();
6116 std::fill(retPtr,retPtr+nbOfCells,-1);
6117 mcIdType newCellId=0;
6118 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6120 for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6121 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6122 retPtr[std::distance(connI,i)]=newCellId++;
6124 renumberCells(retPtr,false);
6129 * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
6130 * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
6131 * This method makes asumption that connectivity is correctly set before calling.
6133 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
6135 checkConnectivityFullyDefined();
6136 const mcIdType *conn=_nodal_connec->begin();
6137 const mcIdType *connI=_nodal_connec_index->begin();
6138 mcIdType nbOfCells=getNumberOfCells();
6139 std::vector<MEDCouplingUMesh *> ret;
6140 for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6142 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6143 mcIdType beginCellId=ToIdType(std::distance(connI,i));
6144 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6145 mcIdType endCellId=ToIdType(std::distance(connI,i));
6146 mcIdType sz=endCellId-beginCellId;
6147 mcIdType *cells=new mcIdType[sz];
6148 for(mcIdType j=0;j<sz;j++)
6149 cells[j]=beginCellId+j;
6150 MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
6158 * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
6159 * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
6160 * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
6162 * \return a newly allocated instance, that the caller must manage.
6163 * \throw If \a this contains more than one geometric type.
6164 * \throw If the nodal connectivity of \a this is not fully defined.
6165 * \throw If the internal data is not coherent.
6167 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
6169 checkConnectivityFullyDefined();
6170 if(_types.size()!=1)
6171 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6172 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6173 MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
6174 ret->setCoords(getCoords());
6175 MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6178 MCAuto<DataArrayIdType> c=convertNodalConnectivityToStaticGeoTypeMesh();
6179 retC->setNodalConnectivity(c);
6183 MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6185 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
6186 DataArrayIdType *c=0,*ci=0;
6187 convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
6188 MCAuto<DataArrayIdType> cs(c),cis(ci);
6189 retD->setNodalConnectivity(cs,cis);
6194 DataArrayIdType *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
6196 checkConnectivityFullyDefined();
6197 if(_types.size()!=1)
6198 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6199 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6200 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6203 std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
6204 oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
6205 throw INTERP_KERNEL::Exception(oss.str());
6207 mcIdType nbCells=getNumberOfCells();
6208 mcIdType typi=ToIdType(typ);
6209 mcIdType nbNodesPerCell=ToIdType(cm.getNumberOfNodes());
6210 MCAuto<DataArrayIdType> connOut=DataArrayIdType::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
6211 mcIdType *outPtr=connOut->getPointer();
6212 const mcIdType *conn=_nodal_connec->begin();
6213 const mcIdType *connI=_nodal_connec_index->begin();
6215 for(mcIdType i=0;i<nbCells;i++,connI++)
6217 if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
6218 outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
6221 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 << ") !";
6222 throw INTERP_KERNEL::Exception(oss.str());
6225 return connOut.retn();
6229 * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
6230 * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
6231 * \param nodalConn nodal connectivity
6232 * \param nodalConnIndex nodal connectivity indices
6234 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayIdType *&nodalConn, DataArrayIdType *&nodalConnIndex) const
6236 static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
6237 checkConnectivityFullyDefined();
6238 if(_types.size()!=1)
6239 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6240 mcIdType nbCells=getNumberOfCells(),
6241 lgth=_nodal_connec->getNumberOfTuples();
6243 throw INTERP_KERNEL::Exception(msg0);
6244 MCAuto<DataArrayIdType> c(DataArrayIdType::New()),ci(DataArrayIdType::New());
6245 c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
6246 mcIdType *cp(c->getPointer()),*cip(ci->getPointer());
6247 const mcIdType *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
6249 for(mcIdType i=0;i<nbCells;i++,cip++,incip++)
6251 mcIdType strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
6252 mcIdType delta(stop-strt);
6255 if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
6256 cp=std::copy(incp+strt,incp+stop,cp);
6258 throw INTERP_KERNEL::Exception(msg0);
6261 throw INTERP_KERNEL::Exception(msg0);
6262 cip[1]=cip[0]+delta;
6264 nodalConn=c.retn(); nodalConnIndex=ci.retn();
6268 * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
6269 * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
6270 * This method is particularly useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
6271 * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
6272 * are not used here to avoid the build of big permutation array.
6274 * \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
6275 * those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6276 * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayIdType instance whose number of tuples is equal to the number of chunks of same geotype
6277 * in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
6278 * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayIdType instance having the same size than \b szOfCellGrpOfSameType. This
6279 * output array gives for each chunck of same type the corresponding mesh id in \b ms.
6280 * \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
6281 * is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6283 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
6284 DataArrayIdType *&szOfCellGrpOfSameType,
6285 DataArrayIdType *&idInMsOfCellGrpOfSameType)
6287 std::vector<const MEDCouplingUMesh *> ms2;
6288 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
6291 (*it)->checkConnectivityFullyDefined();
6295 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
6296 const DataArrayDouble *refCoo=ms2[0]->getCoords();
6297 int meshDim=ms2[0]->getMeshDimension();
6298 std::vector<const MEDCouplingUMesh *> m1ssm;
6299 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
6301 std::vector<const MEDCouplingUMesh *> m1ssmSingle;
6302 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
6303 mcIdType fake=0,rk=0;
6304 MCAuto<DataArrayIdType> ret1(DataArrayIdType::New()),ret2(DataArrayIdType::New());
6305 ret1->alloc(0,1); ret2->alloc(0,1);
6306 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
6308 if(meshDim!=(*it)->getMeshDimension())
6309 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
6310 if(refCoo!=(*it)->getCoords())
6311 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
6312 std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
6313 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
6314 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
6315 for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
6317 MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
6318 m1ssmSingleAuto.push_back(singleCell);
6319 m1ssmSingle.push_back(singleCell);
6320 ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
6323 MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
6324 MCAuto<DataArrayIdType> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
6325 std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
6326 for(mcIdType i=0;i<ToIdType(m1ssm.size());i++)
6327 m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
6328 MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
6329 szOfCellGrpOfSameType=ret1->renumber(renum->begin());
6330 idInMsOfCellGrpOfSameType=ret2->renumber(renum->begin());
6335 * This method returns a newly created DataArrayIdType instance.
6336 * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
6338 DataArrayIdType *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const mcIdType *begin, const mcIdType *end) const
6340 checkFullyDefined();
6341 const mcIdType *conn=_nodal_connec->begin();
6342 const mcIdType *connIndex=_nodal_connec_index->begin();
6343 MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
6344 for(const mcIdType *w=begin;w!=end;w++)
6345 if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
6346 ret->pushBackSilent(*w);
6351 * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
6352 * are in [0:getNumberOfCells())
6354 DataArrayIdType *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayIdType *da) const
6356 checkFullyDefined();
6357 const mcIdType *conn=_nodal_connec->begin();
6358 const mcIdType *connI=_nodal_connec_index->begin();
6359 mcIdType nbOfCells=getNumberOfCells();
6360 std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
6361 mcIdType *tmp=new mcIdType[nbOfCells];
6362 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6365 for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6366 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6367 tmp[std::distance(connI,i)]=j++;
6369 DataArrayIdType *ret=DataArrayIdType::New();
6370 ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
6371 ret->copyStringInfoFrom(*da);
6372 mcIdType *retPtr=ret->getPointer();
6373 const mcIdType *daPtr=da->begin();
6374 mcIdType nbOfElems=da->getNbOfElems();
6375 for(mcIdType k=0;k<nbOfElems;k++)
6376 retPtr[k]=tmp[daPtr[k]];
6382 * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
6383 * This method \b works \b for mesh sorted by type.
6384 * cells whose ids is in 'idsPerGeoType' array.
6385 * This method conserves coords and name of mesh.
6387 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const mcIdType *idsPerGeoTypeBg, const mcIdType *idsPerGeoTypeEnd) const
6389 std::vector<mcIdType> code=getDistributionOfTypes();
6390 std::size_t nOfTypesInThis=code.size()/3;
6391 mcIdType sz=0,szOfType=0;
6392 for(std::size_t i=0;i<nOfTypesInThis;i++)
6397 szOfType=code[3*i+1];
6399 for(const mcIdType *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
6400 if(*work<0 || *work>=szOfType)
6402 std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
6403 oss << ". It should be in [0," << szOfType << ") !";
6404 throw INTERP_KERNEL::Exception(oss.str());
6406 MCAuto<DataArrayIdType> idsTokeep=DataArrayIdType::New(); idsTokeep->alloc(sz+std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
6407 mcIdType *idsPtr=idsTokeep->getPointer();
6409 for(std::size_t i=0;i<nOfTypesInThis;i++)
6412 for(mcIdType j=0;j<code[3*i+1];j++)
6415 idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind2nd(std::plus<mcIdType>(),offset));
6416 offset+=code[3*i+1];
6418 MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
6419 ret->copyTinyInfoFrom(this);
6424 * This method returns a vector of size 'this->getNumberOfCells()'.
6425 * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
6427 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
6429 mcIdType ncell=getNumberOfCells();
6430 std::vector<bool> ret(ncell);
6431 const mcIdType *cI=getNodalConnectivityIndex()->begin();
6432 const mcIdType *c=getNodalConnectivity()->begin();
6433 for(mcIdType i=0;i<ncell;i++)
6435 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
6436 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6437 ret[i]=cm.isQuadratic();
6443 * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
6445 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
6447 if(other->getType()!=UNSTRUCTURED)
6448 throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
6449 const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
6450 return MergeUMeshes(this,otherC);
6454 * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
6455 * computed by averaging coordinates of cell nodes, so this method is not a right
6456 * choice for degenerated meshes (not well oriented, cells with measure close to zero).
6457 * Beware also that for quadratic meshes, degenerated arc of circles are turned into linear edges for the computation.
6458 * This happens with a default detection precision of eps=1.0e-14. If you need control over this use computeCellCenterOfMassWithPrecision().
6459 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6460 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6461 * components. The caller is to delete this array using decrRef() as it is
6463 * \throw If the coordinates array is not set.
6464 * \throw If the nodal connectivity of cells is not defined.
6465 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6466 * \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6468 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
6470 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6471 int spaceDim=getSpaceDimension();
6472 mcIdType nbOfCells=getNumberOfCells();
6473 ret->alloc(nbOfCells,spaceDim);
6474 ret->copyStringInfoFrom(*getCoords());
6475 double *ptToFill=ret->getPointer();
6476 const mcIdType *nodal=_nodal_connec->begin();
6477 const mcIdType *nodalI=_nodal_connec_index->begin();
6478 const double *coor=_coords->begin();
6479 for(mcIdType i=0;i<nbOfCells;i++)
6481 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6482 INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
6490 * See computeCellCenterOfMass().
6491 * \param eps a precision for the detection of degenerated arc of circles.
6492 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6493 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6494 * components. The caller is to delete this array using decrRef() as it is
6496 * \throw If the coordinates array is not set.
6497 * \throw If the nodal connectivity of cells is not defined.
6498 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6499 * \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6501 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMassWithPrecision(double eps) const
6503 INTERP_KERNEL::QuadraticPlanarPrecision prec(eps);
6504 MCAuto<DataArrayDouble> ret = computeCellCenterOfMass();
6510 * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
6511 * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
6513 * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
6514 * DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
6516 * \sa MEDCouplingUMesh::computeCellCenterOfMass
6517 * \throw If \a this is not fully defined (coordinates and connectivity)
6518 * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
6520 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
6522 checkFullyDefined();
6523 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6524 int spaceDim=getSpaceDimension();
6525 mcIdType nbOfCells=getNumberOfCells();
6526 mcIdType nbOfNodes=getNumberOfNodes();
6527 ret->alloc(nbOfCells,spaceDim);
6528 double *ptToFill=ret->getPointer();
6529 const mcIdType *nodal=_nodal_connec->begin();
6530 const mcIdType *nodalI=_nodal_connec_index->begin();
6531 const double *coor=_coords->begin();
6532 for(mcIdType i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
6534 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6535 std::fill(ptToFill,ptToFill+spaceDim,0.);
6536 if(type!=INTERP_KERNEL::NORM_POLYHED)
6538 for(const mcIdType *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
6540 if(*conn>=0 && *conn<nbOfNodes)
6541 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
6544 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," << nbOfNodes << ") !";
6545 throw INTERP_KERNEL::Exception(oss.str());
6548 mcIdType nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
6549 if(nbOfNodesInCell>0)
6550 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
6553 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
6554 throw INTERP_KERNEL::Exception(oss.str());
6559 std::set<mcIdType> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
6561 for(std::set<mcIdType>::const_iterator it=s.begin();it!=s.end();it++)
6563 if(*it>=0 && *it<nbOfNodes)
6564 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
6567 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," << nbOfNodes << ") !";
6568 throw INTERP_KERNEL::Exception(oss.str());
6572 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)s.size()));
6575 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
6576 throw INTERP_KERNEL::Exception(oss.str());
6584 * Returns a new DataArrayDouble holding barycenters of specified cells. The
6585 * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
6586 * are specified via an array of cell ids.
6587 * \warning Validity of the specified cell ids is not checked!
6588 * Valid range is [ 0, \a this->getNumberOfCells() ).
6589 * \param [in] begin - an array of cell ids of interest.
6590 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
6591 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
6592 * end - \a begin ) tuples per \a this->getSpaceDimension() components. The
6593 * caller is to delete this array using decrRef() as it is no more needed.
6594 * \throw If the coordinates array is not set.
6595 * \throw If the nodal connectivity of cells is not defined.
6597 * \if ENABLE_EXAMPLES
6598 * \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
6599 * \ref py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
6602 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const mcIdType *begin, const mcIdType *end) const
6604 DataArrayDouble *ret=DataArrayDouble::New();
6605 int spaceDim=getSpaceDimension();
6606 std::size_t nbOfTuple=std::distance(begin,end);
6607 ret->alloc(nbOfTuple,spaceDim);
6608 double *ptToFill=ret->getPointer();
6609 double *tmp=new double[spaceDim];
6610 const mcIdType *nodal=_nodal_connec->begin();
6611 const mcIdType *nodalI=_nodal_connec_index->begin();
6612 const double *coor=_coords->begin();
6613 for(const mcIdType *w=begin;w!=end;w++)
6615 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
6616 INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
6624 * 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".
6625 * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
6626 * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
6627 * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
6628 * This method is useful to detect 2D cells in 3D space that are not coplanar.
6630 * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
6631 * \throw If spaceDim!=3 or meshDim!=2.
6632 * \throw If connectivity of \a this is invalid.
6633 * \throw If connectivity of a cell in \a this points to an invalid node.
6635 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
6637 MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
6638 mcIdType nbOfCells=getNumberOfCells();
6639 mcIdType nbOfNodes(getNumberOfNodes());
6640 if(getSpaceDimension()!=3 || getMeshDimension()!=2)
6641 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
6642 ret->alloc(nbOfCells,4);
6643 double *retPtr(ret->getPointer());
6644 const mcIdType *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
6645 const double *coor(_coords->begin());
6646 for(mcIdType i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
6648 double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
6649 if(nodalI[1]-nodalI[0]>=4)
6651 double aa[3]={coor[nodal[nodalI[0]+1+1]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6652 coor[nodal[nodalI[0]+1+1]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6653 coor[nodal[nodalI[0]+1+1]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]}
6654 ,bb[3]={coor[nodal[nodalI[0]+1+2]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6655 coor[nodal[nodalI[0]+1+2]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6656 coor[nodal[nodalI[0]+1+2]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]};
6657 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]};
6658 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]));
6659 for(int j=0;j<3;j++)
6661 mcIdType nodeId(nodal[nodalI[0]+1+j]);
6662 if(nodeId>=0 && nodeId<nbOfNodes)
6663 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
6666 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
6667 throw INTERP_KERNEL::Exception(oss.str());
6670 if(sqrt(cc[0]*cc[0]+cc[1]*cc[1]+cc[2]*cc[2])>(1e-3*aa_norm*bb_norm))
6672 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6673 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6677 if(nodalI[1]-nodalI[0]==4)
6679 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : cell" << i << " : Presence of The 3 colinear points !";
6680 throw INTERP_KERNEL::Exception(oss.str());
6683 double dd[3]={0.,0.,0.};
6684 for(mcIdType offset=nodalI[0]+1;offset<nodalI[1];offset++)
6685 std::transform(coor+3*nodal[offset],coor+3*(nodal[offset]+1),dd,dd,std::plus<double>());
6686 mcIdType nbOfNodesInCell(nodalI[1]-nodalI[0]-1);
6687 std::transform(dd,dd+3,dd,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
6688 std::copy(dd,dd+3,matrix+4*2);
6689 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6690 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6695 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
6696 throw INTERP_KERNEL::Exception(oss.str());
6703 * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
6706 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
6709 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
6710 da->checkAllocated();
6711 std::string name(da->getName());
6712 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(name,0));
6714 ret->setName("Mesh");
6716 mcIdType nbOfTuples(da->getNumberOfTuples());
6717 MCAuto<DataArrayIdType> c(DataArrayIdType::New()),cI(DataArrayIdType::New());
6718 c->alloc(2*nbOfTuples,1);
6719 cI->alloc(nbOfTuples+1,1);
6720 mcIdType *cp(c->getPointer()),*cip(cI->getPointer());
6722 for(mcIdType i=0;i<nbOfTuples;i++)
6724 *cp++=INTERP_KERNEL::NORM_POINT1;
6728 ret->setConnectivity(c,cI,true);
6732 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::Build1DMeshFromCoords(DataArrayDouble *da)
6735 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build01MeshFromCoords : instance of DataArrayDouble must be not null !");
6736 da->checkAllocated();
6737 std::string name(da->getName());
6738 MCAuto<MEDCouplingUMesh> ret;
6740 MCAuto<MEDCouplingCMesh> tmp(MEDCouplingCMesh::New());
6741 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6742 arr->alloc(da->getNumberOfTuples());
6743 tmp->setCoordsAt(0,arr);
6744 ret=tmp->buildUnstructured();
6748 ret->setName("Mesh");
6755 * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
6756 * Cells and nodes of
6757 * the first mesh precede cells and nodes of the second mesh within the result mesh.
6758 * \param [in] mesh1 - the first mesh.
6759 * \param [in] mesh2 - the second mesh.
6760 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6761 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6762 * is no more needed.
6763 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6764 * \throw If the coordinates array is not set in none of the meshes.
6765 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6766 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6768 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6770 std::vector<const MEDCouplingUMesh *> tmp(2);
6771 tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
6772 return MergeUMeshes(tmp);
6776 * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
6777 * Cells and nodes of
6778 * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
6779 * \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
6780 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6781 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6782 * is no more needed.
6783 * \throw If \a a.size() == 0.
6784 * \throw If \a a[ *i* ] == NULL.
6785 * \throw If the coordinates array is not set in none of the meshes.
6786 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
6787 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6789 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const std::vector<const MEDCouplingUMesh *>& a)
6791 std::size_t sz=a.size();
6793 return MergeUMeshesLL(a);
6794 for(std::size_t ii=0;ii<sz;ii++)
6797 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
6798 throw INTERP_KERNEL::Exception(oss.str());
6800 std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
6801 std::vector< const MEDCouplingUMesh * > aa(sz);
6803 for(std::size_t i=0;i<sz && spaceDim==-3;i++)
6805 const MEDCouplingUMesh *cur=a[i];
6806 const DataArrayDouble *coo=cur->getCoords();
6808 spaceDim=int(coo->getNumberOfComponents());
6811 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
6812 for(std::size_t i=0;i<sz;i++)
6814 bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
6817 return MergeUMeshesLL(aa);
6821 * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
6822 * dimension and sharing the node coordinates array.
6823 * All cells of the first mesh precede all cells of the second mesh
6824 * within the result mesh.
6825 * \param [in] mesh1 - the first mesh.
6826 * \param [in] mesh2 - the second mesh.
6827 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6828 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6829 * is no more needed.
6830 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6831 * \throw If the meshes do not share the node coordinates array.
6832 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6833 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6835 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6837 std::vector<const MEDCouplingUMesh *> tmp(2);
6838 tmp[0]=mesh1; tmp[1]=mesh2;
6839 return MergeUMeshesOnSameCoords(tmp);
6843 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6844 * dimension and sharing the node coordinates array.
6845 * All cells of the *i*-th mesh precede all cells of the
6846 * (*i*+1)-th mesh within the result mesh.
6847 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
6848 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6849 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6850 * is no more needed.
6851 * \throw If \a a.size() == 0.
6852 * \throw If \a a[ *i* ] == NULL.
6853 * \throw If the meshes do not share the node coordinates array.
6854 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
6855 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6857 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
6860 throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
6861 for(std::size_t ii=0;ii<meshes.size();ii++)
6864 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
6865 throw INTERP_KERNEL::Exception(oss.str());
6867 const DataArrayDouble *coords=meshes.front()->getCoords();
6868 int meshDim=meshes.front()->getMeshDimension();
6869 std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
6870 mcIdType meshLgth=0;
6871 mcIdType meshIndexLgth=0;
6872 for(;iter!=meshes.end();iter++)
6874 if(coords!=(*iter)->getCoords())
6875 throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
6876 if(meshDim!=(*iter)->getMeshDimension())
6877 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
6878 meshLgth+=(*iter)->getNodalConnectivityArrayLen();
6879 meshIndexLgth+=(*iter)->getNumberOfCells();
6881 MCAuto<DataArrayIdType> nodal=DataArrayIdType::New();
6882 nodal->alloc(meshLgth,1);
6883 mcIdType *nodalPtr=nodal->getPointer();
6884 MCAuto<DataArrayIdType> nodalIndex=DataArrayIdType::New();
6885 nodalIndex->alloc(meshIndexLgth+1,1);
6886 mcIdType *nodalIndexPtr=nodalIndex->getPointer();
6888 for(iter=meshes.begin();iter!=meshes.end();iter++)
6890 const mcIdType *nod=(*iter)->getNodalConnectivity()->begin();
6891 const mcIdType *index=(*iter)->getNodalConnectivityIndex()->begin();
6892 mcIdType nbOfCells=(*iter)->getNumberOfCells();
6893 mcIdType meshLgth2=(*iter)->getNodalConnectivityArrayLen();
6894 nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
6895 if(iter!=meshes.begin())
6896 nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind2nd(std::plus<mcIdType>(),offset));
6898 nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
6901 MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
6902 ret->setName("merge");
6903 ret->setMeshDimension(meshDim);
6904 ret->setConnectivity(nodal,nodalIndex,true);
6905 ret->setCoords(coords);
6910 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6911 * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
6912 * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
6913 * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
6914 * New" mode are returned for each input mesh.
6915 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
6916 * \param [in] compType - specifies a cell comparison technique. For meaning of its
6917 * valid values [0,1,2], see zipConnectivityTraducer().
6918 * \param [in,out] corr - an array of DataArrayIdType, of the same size as \a
6919 * meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
6920 * mesh. The caller is to delete each of the arrays using decrRef() as it is
6922 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6923 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6924 * is no more needed.
6925 * \throw If \a meshes.size() == 0.
6926 * \throw If \a meshes[ *i* ] == NULL.
6927 * \throw If the meshes do not share the node coordinates array.
6928 * \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
6929 * \throw If the \a meshes are of different dimension (getMeshDimension()).
6930 * \throw If the nodal connectivity of cells of any of \a meshes is not defined.
6931 * \throw If the nodal connectivity any of \a meshes includes an invalid id.
6933 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayIdType *>& corr)
6935 //All checks are delegated to MergeUMeshesOnSameCoords
6936 MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
6937 MCAuto<DataArrayIdType> o2n=ret->zipConnectivityTraducer(compType);
6938 corr.resize(meshes.size());
6939 std::size_t nbOfMeshes=meshes.size();
6941 const mcIdType *o2nPtr=o2n->begin();
6942 for(std::size_t i=0;i<nbOfMeshes;i++)
6944 DataArrayIdType *tmp=DataArrayIdType::New();
6945 mcIdType curNbOfCells=meshes[i]->getNumberOfCells();
6946 tmp->alloc(curNbOfCells,1);
6947 std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
6948 offset+=curNbOfCells;
6949 tmp->setName(meshes[i]->getName());
6956 * Makes all given meshes share the nodal connectivity array. The common connectivity
6957 * array is created by concatenating the connectivity arrays of all given meshes. All
6958 * the given meshes must be of the same space dimension but dimension of cells **can
6959 * differ**. This method is particularly useful in MEDLoader context to build a \ref
6960 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
6961 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
6962 * \param [in,out] meshes - a vector of meshes to update.
6963 * \throw If any of \a meshes is NULL.
6964 * \throw If the coordinates array is not set in any of \a meshes.
6965 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
6966 * \throw If \a meshes are of different space dimension.
6968 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
6970 std::size_t sz=meshes.size();
6973 std::vector< const DataArrayDouble * > coords(meshes.size());
6974 std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
6975 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
6979 (*it)->checkConnectivityFullyDefined();
6980 const DataArrayDouble *coo=(*it)->getCoords();
6985 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
6986 oss << " has no coordinate array defined !";
6987 throw INTERP_KERNEL::Exception(oss.str());
6992 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
6993 oss << " is null !";
6994 throw INTERP_KERNEL::Exception(oss.str());
6997 MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
6998 std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
6999 mcIdType offset=(*it)->getNumberOfNodes();
7000 (*it++)->setCoords(res);
7001 for(;it!=meshes.end();it++)
7003 mcIdType oldNumberOfNodes=(*it)->getNumberOfNodes();
7004 (*it)->setCoords(res);
7005 (*it)->shiftNodeNumbersInConn(offset);
7006 offset+=oldNumberOfNodes;
7011 * Merges nodes coincident with a given precision within all given meshes that share
7012 * the nodal connectivity array. The given meshes **can be of different** mesh
7013 * dimension. This method is particularly useful in MEDLoader context to build a \ref
7014 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
7015 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
7016 * \param [in,out] meshes - a vector of meshes to update.
7017 * \param [in] eps - the precision used to detect coincident nodes (infinite norm).
7018 * \throw If any of \a meshes is NULL.
7019 * \throw If the \a meshes do not share the same node coordinates array.
7020 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
7022 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
7026 std::set<const DataArrayDouble *> s;
7027 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7030 s.insert((*it)->getCoords());
7033 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 !";
7034 throw INTERP_KERNEL::Exception(oss.str());
7039 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 !";
7040 throw INTERP_KERNEL::Exception(oss.str());
7042 const DataArrayDouble *coo=*(s.begin());
7046 DataArrayIdType *comm,*commI;
7047 coo->findCommonTuples(eps,-1,comm,commI);
7048 MCAuto<DataArrayIdType> tmp1(comm),tmp2(commI);
7049 mcIdType oldNbOfNodes=coo->getNumberOfTuples();
7050 mcIdType newNbOfNodes;
7051 MCAuto<DataArrayIdType> o2n=DataArrayIdType::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
7052 if(oldNbOfNodes==newNbOfNodes)
7054 MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->begin(),newNbOfNodes);
7055 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7057 (*it)->renumberNodesInConn(o2n->begin());
7058 (*it)->setCoords(newCoords);
7064 * This static operates only for coords in 3D. The polygon is specified by its connectivity nodes in [ \a begin , \a end ).
7066 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const mcIdType *begin, const mcIdType *end, const double *coords)
7069 double v[3]={0.,0.,0.};
7070 std::size_t sz=std::distance(begin,end);
7074 // Algorithm: sum in v the cross products of (e1, e2) where e_i it the vector between (0,0,0) and point i
7075 // and e2 is linear point directly following e1 in the connectivity. All points are used.
7076 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];
7077 v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
7078 v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
7082 // Same algorithm as above but also using intermediate quadratic points.
7083 // (taking only linear points might lead to issues if the linearized version of the
7084 // polygon is not convex or self-intersecting ... see testCellOrientation4)
7085 std::size_t hsz = sz/2;
7086 for(std::size_t j=0;j<sz;j++)
7088 if (j%2) // current point i is quadratic, next point i+1 is standard
7091 ip1 = ((j-1)/2 + 1)%hsz; // ip1 means "i+1", i.e. next point
7093 else // current point i is standard, next point i+1 is quadratic
7098 v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
7099 v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
7100 v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
7103 double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
7108 * The polyhedron is specified by its connectivity nodes in [ \a begin , \a end ).
7110 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7112 std::vector<std::pair<mcIdType,mcIdType> > edges;
7113 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7114 const mcIdType *bgFace=begin;
7115 for(std::size_t i=0;i<nbOfFaces;i++)
7117 const mcIdType *endFace=std::find(bgFace+1,end,-1);
7118 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7119 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7121 std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7122 if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
7124 edges.push_back(p1);
7128 return INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)>-EPS_FOR_POLYH_ORIENTATION;
7132 * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
7134 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7136 double vec0[3],vec1[3];
7137 std::size_t sz=std::distance(begin,end);
7139 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
7140 mcIdType nbOfNodes=ToIdType(sz/2);
7141 INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
7142 const double *pt0=coords+3*begin[0];
7143 const double *pt1=coords+3*begin[nbOfNodes];
7144 vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
7145 return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
7148 void MEDCouplingUMesh::CorrectExtrudedStaticCell(mcIdType *begin, mcIdType *end)
7150 std::size_t sz=std::distance(begin,end);
7151 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz];
7152 std::size_t nbOfNodes(sz/2);
7153 std::copy(begin,end,(mcIdType *)tmp);
7154 for(std::size_t j=1;j<nbOfNodes;j++)
7156 begin[j]=tmp[nbOfNodes-j];
7157 begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
7161 bool MEDCouplingUMesh::IsTetra4WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7163 std::size_t sz=std::distance(begin,end);
7165 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
7166 double vec0[3],vec1[3];
7167 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
7168 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];
7169 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;
7172 bool MEDCouplingUMesh::IsPyra5WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7174 std::size_t sz=std::distance(begin,end);
7176 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
7178 INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
7179 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
7180 return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
7184 * 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 )
7185 * 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
7188 * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
7189 * \param [in] coords the coordinates with nb of components exactly equal to 3
7190 * \param [in] index begin of the nodal connectivity (geometric type included) of a single polyhedron cell
7191 * \param [out] res the result is put at the end of the vector without any alteration of the data.
7193 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, mcIdType index, DataArrayIdType *res, MEDCouplingUMesh *faces,
7194 DataArrayIdType *E_Fi, DataArrayIdType *E_F, DataArrayIdType *F_Ei, DataArrayIdType *F_E)
7196 mcIdType nbFaces = E_Fi->getIJ(index + 1, 0) - E_Fi->getIJ(index, 0);
7197 MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
7198 double *vPtr=v->getPointer();
7199 MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,2);
7200 double *pPtr=p->getPointer();
7201 mcIdType *e_fi = E_Fi->getPointer(), *e_f = E_F->getPointer(), *f_ei = F_Ei->getPointer(), *f_e = F_E->getPointer();
7202 const mcIdType *f_idx = faces->getNodalConnectivityIndex()->getPointer(), *f_cnn = faces->getNodalConnectivity()->getPointer();
7203 for(mcIdType i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
7205 mcIdType face = e_f[e_fi[index] + i];
7206 ComputeVecAndPtOfFace(eps, coords->begin(), f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1], vPtr, pPtr);
7207 // to differentiate faces going to different cells:
7209 for (mcIdType j = f_ei[face]; j < f_ei[face + 1]; j++)
7210 *pPtr += FromIdType<double>(f_e[j]);
7212 pPtr=p->getPointer(); vPtr=v->getPointer();
7213 DataArrayIdType *comm1=0,*commI1=0;
7214 v->findCommonTuples(eps,-1,comm1,commI1);
7215 for (mcIdType i = 0; i < nbFaces; i++)
7216 if (comm1->findIdFirstEqual(i) < 0)
7218 comm1->pushBackSilent(i);
7219 commI1->pushBackSilent(comm1->getNumberOfTuples());
7221 MCAuto<DataArrayIdType> comm1Auto(comm1),commI1Auto(commI1);
7222 const mcIdType *comm1Ptr=comm1->begin();
7223 const mcIdType *commI1Ptr=commI1->begin();
7224 mcIdType nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
7225 res->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYHED));
7227 for(mcIdType i=0;i<nbOfGrps1;i++)
7229 mcIdType vecId=comm1Ptr[commI1Ptr[i]];
7230 MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7231 DataArrayIdType *comm2=0,*commI2=0;
7232 tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
7233 for (mcIdType j = 0; j < commI1Ptr[i+1] - commI1Ptr[i]; j++)
7234 if (comm2->findIdFirstEqual(j) < 0)
7236 comm2->pushBackSilent(j);
7237 commI2->pushBackSilent(comm2->getNumberOfTuples());
7239 MCAuto<DataArrayIdType> comm2Auto(comm2),commI2Auto(commI2);
7240 const mcIdType *comm2Ptr=comm2->begin();
7241 const mcIdType *commI2Ptr=commI2->begin();
7242 mcIdType nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
7243 for(mcIdType j=0;j<nbOfGrps2;j++)
7245 if(commI2Ptr[j+1] == commI2Ptr[j] + 1)
7247 mcIdType face = e_f[e_fi[index] + comm1Ptr[commI1Ptr[i] + comm2Ptr[commI2Ptr[j]]]]; //hmmm
7248 res->insertAtTheEnd(f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1]);
7249 res->pushBackSilent(-1);
7253 mcIdType pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
7254 MCAuto<DataArrayIdType> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
7255 ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7256 ids2->transformWithIndArr(e_f + e_fi[index], e_f + e_fi[index + 1]);
7257 MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(faces->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
7258 MCAuto<DataArrayIdType> idsNodeTmp=mm3->zipCoordsTraducer();
7259 MCAuto<DataArrayIdType> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
7260 const mcIdType *idsNodePtr=idsNode->begin();
7261 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];
7262 double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
7263 double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
7264 if(std::abs(norm)>eps)
7266 double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
7267 mm3->rotate(center,vec,angle);
7269 mm3->changeSpaceDimension(2);
7270 MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
7271 const mcIdType *conn4=mm4->getNodalConnectivity()->begin();
7272 const mcIdType *connI4=mm4->getNodalConnectivityIndex()->begin();
7273 mcIdType nbOfCells=mm4->getNumberOfCells();
7274 for(mcIdType k=0;k<nbOfCells;k++)
7277 for(const mcIdType *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
7278 res->pushBackSilent(idsNodePtr[*work]);
7279 res->pushBackSilent(-1);
7284 res->popBackSilent();
7288 * 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
7289 * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
7291 * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
7292 * \param [in] coords coordinates expected to have 3 components.
7293 * \param [in] begin start of the nodal connectivity of the face.
7294 * \param [in] end end of the nodal connectivity (excluded) of the face.
7295 * \param [out] v the normalized vector of size 3
7296 * \param [out] p the pos of plane
7298 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const mcIdType *begin, const mcIdType *end, double *v, double *p)
7300 std::size_t nbPoints=std::distance(begin,end);
7302 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
7303 double vec[3]={0.,0.,0.};
7305 bool refFound=false;
7306 for(;j<nbPoints-1 && !refFound;j++)
7308 vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
7309 vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
7310 vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
7311 double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
7315 vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
7318 for(std::size_t i=j;i<nbPoints-1;i++)
7321 curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
7322 curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
7323 curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
7324 double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
7327 curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
7328 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];
7329 norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
7332 v[0]/=norm; v[1]/=norm; v[2]/=norm;
7333 *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
7337 throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
7341 * This method tries to obtain a well oriented polyhedron.
7342 * If the algorithm fails, an exception will be thrown.
7344 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(mcIdType *begin, mcIdType *end, const double *coords)
7346 std::list< std::pair<mcIdType,mcIdType> > edgesOK,edgesFinished;
7347 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7348 std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
7350 mcIdType *bgFace=begin,*endFace=std::find(begin+1,end,-1);
7351 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7352 for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<mcIdType,mcIdType> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
7354 while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
7357 std::size_t smthChanged=0;
7358 for(std::size_t i=0;i<nbOfFaces;i++)
7360 endFace=std::find(bgFace+1,end,-1);
7361 nbOfEdgesInFace=std::distance(bgFace,endFace);
7365 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7367 std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7368 std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7369 bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
7370 bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
7371 if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
7376 std::reverse(bgFace+1,endFace);
7377 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7379 std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7380 std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7381 if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
7382 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7383 if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
7384 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7385 std::list< std::pair<mcIdType,mcIdType> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
7386 if(it!=edgesOK.end())
7389 edgesFinished.push_back(p1);
7392 edgesOK.push_back(p1);
7399 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
7401 if(!edgesOK.empty())
7402 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
7403 if(INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)<-EPS_FOR_POLYH_ORIENTATION)
7404 {//not lucky ! The first face was not correctly oriented : reorient all faces...
7406 for(std::size_t i=0;i<nbOfFaces;i++)
7408 endFace=std::find(bgFace+1,end,-1);
7409 std::reverse(bgFace+1,endFace);
7417 * This method makes the assumption spacedimension == meshdimension == 2.
7418 * This method works only for linear cells.
7420 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
7422 DataArrayIdType *MEDCouplingUMesh::buildUnionOf2DMesh() const
7424 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
7425 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
7426 MCAuto<MEDCouplingUMesh> skin(computeSkin());
7427 mcIdType oldNbOfNodes(skin->getNumberOfNodes());
7428 MCAuto<DataArrayIdType> o2n(skin->zipCoordsTraducer());
7429 mcIdType nbOfNodesExpected(skin->getNumberOfNodes());
7430 MCAuto<DataArrayIdType> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
7431 mcIdType nbCells=skin->getNumberOfCells();
7432 if(nbCells==nbOfNodesExpected)
7433 return buildUnionOf2DMeshLinear(skin,n2o);
7434 else if(2*nbCells==nbOfNodesExpected)
7435 return buildUnionOf2DMeshQuadratic(skin,n2o);
7437 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
7441 * This method makes the assumption spacedimension == meshdimension == 3.
7442 * This method works only for linear cells.
7444 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
7446 DataArrayIdType *MEDCouplingUMesh::buildUnionOf3DMesh() const
7448 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
7449 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
7450 MCAuto<MEDCouplingUMesh> m=computeSkin();
7451 const mcIdType *conn=m->getNodalConnectivity()->begin();
7452 const mcIdType *connI=m->getNodalConnectivityIndex()->begin();
7453 mcIdType nbOfCells=m->getNumberOfCells();
7454 MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
7455 mcIdType *work=ret->getPointer(); *work++=INTERP_KERNEL::NORM_POLYHED;
7458 work=std::copy(conn+connI[0]+1,conn+connI[1],work);
7459 for(mcIdType i=1;i<nbOfCells;i++)
7462 work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
7468 * \brief Creates a graph of cell neighbors
7469 * \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
7470 * In the sky line array, graph arcs are stored in terms of (index,value) notation.
7472 * - index: 0 3 5 6 6
7473 * - value: 1 2 3 2 3 3
7474 * means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7475 * Arcs are not doubled but reflexive (1,1) arcs are present for each cell
7477 MEDCouplingSkyLineArray* MEDCouplingUMesh::generateGraph() const
7479 checkConnectivityFullyDefined();
7481 int meshDim = this->getMeshDimension();
7482 MEDCoupling::DataArrayIdType* indexr=MEDCoupling::DataArrayIdType::New();
7483 MEDCoupling::DataArrayIdType* revConn=MEDCoupling::DataArrayIdType::New();
7484 this->getReverseNodalConnectivity(revConn,indexr);
7485 const mcIdType* indexr_ptr=indexr->begin();
7486 const mcIdType* revConn_ptr=revConn->begin();
7488 const MEDCoupling::DataArrayIdType* index;
7489 const MEDCoupling::DataArrayIdType* conn;
7490 conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
7491 index=this->getNodalConnectivityIndex();
7492 mcIdType nbCells=this->getNumberOfCells();
7493 const mcIdType* index_ptr=index->begin();
7494 const mcIdType* conn_ptr=conn->begin();
7496 //creating graph arcs (cell to cell relations)
7497 //arcs are stored in terms of (index,value) notation
7500 // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7501 // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
7503 //warning here one node have less than or equal effective number of cell with it
7504 //but cell could have more than effective nodes
7505 //because other equals nodes in other domain (with other global inode)
7506 std::vector <mcIdType> cell2cell_index(nbCells+1,0);
7507 std::vector <mcIdType> cell2cell;
7508 cell2cell.reserve(3*nbCells);
7510 for (mcIdType icell=0; icell<nbCells;icell++)
7512 std::map<mcIdType,mcIdType > counter;
7513 for (mcIdType iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
7515 mcIdType inode=conn_ptr[iconn];
7516 for (mcIdType iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
7518 mcIdType icell2=revConn_ptr[iconnr];
7519 std::map<mcIdType,mcIdType>::iterator iter=counter.find(icell2);
7520 if (iter!=counter.end()) (iter->second)++;
7521 else counter.insert(std::make_pair(icell2,1));
7524 for (std::map<mcIdType,mcIdType>::const_iterator iter=counter.begin();
7525 iter!=counter.end(); iter++)
7526 if (iter->second >= meshDim)
7528 cell2cell_index[icell+1]++;
7529 cell2cell.push_back(iter->first);
7534 cell2cell_index[0]=0;
7535 for (mcIdType icell=0; icell<nbCells;icell++)
7536 cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
7538 //filling up index and value to create skylinearray structure
7539 MEDCouplingSkyLineArray * array(MEDCouplingSkyLineArray::New(cell2cell_index,cell2cell));
7544 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
7546 mcIdType nbOfCells=getNumberOfCells();
7548 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
7549 ofs << " <" << getVTKDataSetType() << ">\n";
7550 ofs << " <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
7551 ofs << " <PointData>\n" << pointData << std::endl;
7552 ofs << " </PointData>\n";
7553 ofs << " <CellData>\n" << cellData << std::endl;
7554 ofs << " </CellData>\n";
7555 ofs << " <Points>\n";
7556 if(getSpaceDimension()==3)
7557 _coords->writeVTK(ofs,8,"Points",byteData);
7560 MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
7561 coo->writeVTK(ofs,8,"Points",byteData);
7563 ofs << " </Points>\n";
7564 ofs << " <Cells>\n";
7565 const mcIdType *cPtr=_nodal_connec->begin();
7566 const mcIdType *cIPtr=_nodal_connec_index->begin();
7567 MCAuto<DataArrayIdType> faceoffsets=DataArrayIdType::New(); faceoffsets->alloc(nbOfCells,1);
7568 MCAuto<DataArrayIdType> types=DataArrayIdType::New(); types->alloc(nbOfCells,1);
7569 MCAuto<DataArrayIdType> offsets=DataArrayIdType::New(); offsets->alloc(nbOfCells,1);
7570 MCAuto<DataArrayIdType> connectivity=DataArrayIdType::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
7571 mcIdType *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
7572 mcIdType szFaceOffsets=0,szConn=0;
7573 for(mcIdType i=0;i<nbOfCells;i++,w1++,w2++,w3++)
7576 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
7579 *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
7580 w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
7584 mcIdType deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
7585 *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
7586 std::set<mcIdType> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
7587 *w3=szConn+ToIdType(c.size()); szConn+=ToIdType(c.size());
7588 w4=std::copy(c.begin(),c.end(),w4);
7591 std::unique_ptr<mcIdType[]> medcoupling2vtkTypeTraducer_mcIdType(new mcIdType[MEDCOUPLING2VTKTYPETRADUCER_LGTH]);
7592 for(auto ii = 0; ii<MEDCOUPLING2VTKTYPETRADUCER_LGTH ; ++ii)
7593 medcoupling2vtkTypeTraducer_mcIdType[ii] = MEDCOUPLING2VTKTYPETRADUCER[ii]!=MEDCOUPLING2VTKTYPETRADUCER_NONE?MEDCOUPLING2VTKTYPETRADUCER[ii] : -1;
7594 types->transformWithIndArr(medcoupling2vtkTypeTraducer_mcIdType.get(),medcoupling2vtkTypeTraducer_mcIdType.get()+MEDCOUPLING2VTKTYPETRADUCER_LGTH);
7595 types->writeVTK(ofs,8,"UInt8","types",byteData);
7596 std::string vtkTypeName = Traits<mcIdType>::VTKReprStr;
7597 offsets->writeVTK(ofs,8,vtkTypeName,"offsets",byteData);
7598 if(szFaceOffsets!=0)
7599 {//presence of Polyhedra
7600 connectivity->reAlloc(szConn);
7601 faceoffsets->writeVTK(ofs,8,vtkTypeName,"faceoffsets",byteData);
7602 MCAuto<DataArrayIdType> faces=DataArrayIdType::New(); faces->alloc(szFaceOffsets,1);
7603 w1=faces->getPointer();
7604 for(mcIdType i=0;i<nbOfCells;i++)
7605 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
7607 mcIdType nbFaces=ToIdType(std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1))+1;
7609 const mcIdType *w6=cPtr+cIPtr[i]+1,*w5=0;
7610 for(mcIdType j=0;j<nbFaces;j++)
7612 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
7613 *w1++=ToIdType(std::distance(w6,w5));
7614 w1=std::copy(w6,w5,w1);
7618 faces->writeVTK(ofs,8,vtkTypeName,"faces",byteData);
7620 connectivity->writeVTK(ofs,8,vtkTypeName,"connectivity",byteData);
7621 ofs << " </Cells>\n";
7622 ofs << " </Piece>\n";
7623 ofs << " </" << getVTKDataSetType() << ">\n";
7626 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
7628 stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
7630 { stream << " Not set !"; return ; }
7631 stream << " Mesh dimension : " << _mesh_dim << ".";
7635 { stream << " No coordinates set !"; return ; }
7636 if(!_coords->isAllocated())
7637 { stream << " Coordinates set but not allocated !"; return ; }
7638 stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
7639 stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
7640 if(!_nodal_connec_index)
7641 { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
7642 if(!_nodal_connec_index->isAllocated())
7643 { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
7644 mcIdType lgth=_nodal_connec_index->getNumberOfTuples();
7645 std::size_t cpt=_nodal_connec_index->getNumberOfComponents();
7646 if(cpt!=1 || lgth<1)
7648 stream << std::endl << "Number of cells : " << lgth-1 << ".";
7651 std::string MEDCouplingUMesh::getVTKDataSetType() const
7653 return std::string("UnstructuredGrid");
7656 std::string MEDCouplingUMesh::getVTKFileExtension() const
7658 return std::string("vtu");
7664 * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
7665 * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
7666 * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
7667 * The caller is to deal with the resulting DataArrayIdType.
7668 * \throw If the coordinate array is not set.
7669 * \throw If the nodal connectivity of the cells is not defined.
7670 * \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
7671 * \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
7673 * \sa DataArrayIdType::sortEachPairToMakeALinkedList
7675 DataArrayIdType *MEDCouplingUMesh::orderConsecutiveCells1D() const
7677 checkFullyDefined();
7678 if(getMeshDimension()!=1)
7679 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
7681 // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
7682 MCAuto<DataArrayIdType> _d(DataArrayIdType::New()),_dI(DataArrayIdType::New());
7683 MCAuto<DataArrayIdType> _rD(DataArrayIdType::New()),_rDI(DataArrayIdType::New());
7684 MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
7685 const mcIdType *d(_d->begin()), *dI(_dI->begin());
7686 const mcIdType *rD(_rD->begin()), *rDI(_rDI->begin());
7687 MCAuto<DataArrayIdType> _dsi(_rDI->deltaShiftIndex());
7688 const mcIdType * dsi(_dsi->begin());
7689 MCAuto<DataArrayIdType> dsii = _dsi->findIdsNotInRange(0,3);
7691 if (dsii->getNumberOfTuples())
7692 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
7694 mcIdType nc=getNumberOfCells();
7695 MCAuto<DataArrayIdType> result(DataArrayIdType::New());
7696 result->alloc(nc,1);
7698 // set of edges not used so far
7699 std::set<mcIdType> edgeSet;
7700 for (mcIdType i=0; i<nc; edgeSet.insert(i), i++);
7702 mcIdType startSeg=0;
7704 // while we have points with only one neighbor segments
7707 std::list<mcIdType> linePiece;
7708 // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
7709 for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
7711 // Fill the list forward (resp. backward) from the start segment:
7712 mcIdType activeSeg = startSeg;
7713 mcIdType prevPointId = -20;
7715 while (!edgeSet.empty())
7717 if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
7720 linePiece.push_back(activeSeg);
7722 linePiece.push_front(activeSeg);
7723 edgeSet.erase(activeSeg);
7726 mcIdType ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
7727 ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
7728 if (dsi[ptId] == 1) // hitting the end of the line
7731 mcIdType seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
7732 activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
7735 // Done, save final piece into DA:
7736 std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
7737 newIdx += ToIdType(linePiece.size());
7739 // identify next valid start segment (one which is not consumed)
7740 if(!edgeSet.empty())
7741 startSeg = *(edgeSet.begin());
7743 while (!edgeSet.empty());
7744 return result.retn();
7748 * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
7749 * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
7750 * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
7751 * a minimal creation of new nodes is wanted.
7752 * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
7753 * nodes if a SEG3 is split without information of middle.
7754 * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
7755 * avoid to have a non conform mesh.
7757 * \return mcIdType - the number of new nodes created (in most of cases 0).
7759 * \throw If \a this is not coherent.
7760 * \throw If \a this has not spaceDim equal to 2.
7761 * \throw If \a this has not meshDim equal to 2.
7762 * \throw If some subcells needed to be split are orphan.
7763 * \sa MEDCouplingUMesh::conformize2D
7765 mcIdType MEDCouplingUMesh::split2DCells(const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *subNodesInSeg, const DataArrayIdType *subNodesInSegI, const DataArrayIdType *midOpt, const DataArrayIdType *midOptI)
7767 if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
7768 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
7769 desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
7770 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
7771 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
7772 if(midOpt==0 && midOptI==0)
7774 split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
7777 else if(midOpt!=0 && midOptI!=0)
7778 return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
7780 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
7784 * 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
7785 * 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
7786 * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
7787 * 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
7788 * 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.
7790 * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
7792 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const mcIdType *nodalConnBg, const mcIdType *nodalConnEnd, DataArrayIdType *nodalConnecOut)
7794 std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
7797 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
7798 if(cm.getDimension()==2)
7800 const mcIdType *node=nodalConnBg+1;
7801 mcIdType startNode=*node++;
7802 double refX=coords[2*startNode];
7803 for(;node!=nodalConnEnd;node++)
7805 if(coords[2*(*node)]<refX)
7808 refX=coords[2*startNode];
7811 std::vector<mcIdType> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
7815 double angle0=-M_PI/2;
7817 mcIdType nextNode=-1;
7818 mcIdType prevNode=-1;
7820 double angleNext=0.;
7821 while(nextNode!=startNode)
7825 for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
7827 if(*node!=tmpOut.back() && *node!=prevNode)
7829 tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
7830 double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
7835 res=angle0-angleM+2.*M_PI;
7844 if(nextNode!=startNode)
7846 angle0=angleNext-M_PI;
7849 prevNode=tmpOut.back();
7850 tmpOut.push_back(nextNode);
7853 std::vector<mcIdType> tmp3(2*(sz-1));
7854 std::vector<mcIdType>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
7855 std::copy(nodalConnBg+1,nodalConnEnd,it);
7856 if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
7858 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
7861 if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
7863 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
7868 nodalConnecOut->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
7869 nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
7874 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7877 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7881 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
7882 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
7883 * 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]].
7884 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
7885 * A negative value in \b arrIn means that it is ignored.
7886 * 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.
7888 * \param [in] arrIn arr origin array from which the extraction will be done.
7889 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7890 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
7891 * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
7893 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
7895 mcIdType seed=0,nbOfDepthPeelingPerformed=0;
7896 return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
7900 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
7901 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
7902 * 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]].
7903 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
7904 * A negative value in \b arrIn means that it is ignored.
7905 * 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.
7906 * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
7907 * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
7908 * \param [in] arrIn arr origin array from which the extraction will be done.
7909 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7910 * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
7911 * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
7912 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
7913 * \sa MEDCouplingUMesh::partitionBySpreadZone
7915 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const mcIdType *seedBg, const mcIdType *seedEnd, const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn, mcIdType nbOfDepthPeeling, mcIdType& nbOfDepthPeelingPerformed)
7917 nbOfDepthPeelingPerformed=0;
7919 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
7920 mcIdType nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7923 DataArrayIdType *ret=DataArrayIdType::New(); ret->alloc(0,1);
7927 std::vector<bool> fetched(nbOfTuples,false);
7928 return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
7934 * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
7935 * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
7936 * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
7937 * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
7938 * The sum of measure field of returned mesh is equal to the sum of measure field of this.
7940 * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
7942 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
7944 checkFullyDefined();
7945 int mdim=getMeshDimension();
7946 int spaceDim=getSpaceDimension();
7948 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
7949 std::vector<DataArrayIdType *> partition=partitionBySpreadZone();
7950 std::vector< MCAuto<DataArrayIdType> > partitionAuto; partitionAuto.reserve(partition.size());
7951 std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayIdType> > >(partitionAuto));
7952 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
7953 ret->setCoords(getCoords());
7954 ret->allocateCells(ToIdType(partition.size()));
7956 for(std::vector<DataArrayIdType *>::const_iterator it=partition.begin();it!=partition.end();it++)
7958 MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
7959 MCAuto<DataArrayIdType> cell;
7963 cell=tmp->buildUnionOf2DMesh();
7966 cell=tmp->buildUnionOf3DMesh();
7969 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
7972 ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->begin()+1);
7975 ret->finishInsertingCells();
7980 * This method partitions \b this into contiguous zone.
7981 * This method only needs a well defined connectivity. Coordinates are not considered here.
7982 * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
7984 std::vector<DataArrayIdType *> MEDCouplingUMesh::partitionBySpreadZone() const
7986 DataArrayIdType *neigh=0,*neighI=0;
7987 computeNeighborsOfCells(neigh,neighI);
7988 MCAuto<DataArrayIdType> neighAuto(neigh),neighIAuto(neighI);
7989 return PartitionBySpreadZone(neighAuto,neighIAuto);
7992 std::vector<DataArrayIdType *> MEDCouplingUMesh::PartitionBySpreadZone(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
7994 if(!arrIn || !arrIndxIn)
7995 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : null input pointers !");
7996 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
7997 mcIdType nbOfTuples(arrIndxIn->getNumberOfTuples());
7998 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1 || nbOfTuples<1)
7999 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : invalid arrays in input !");
8000 mcIdType nbOfCellsCur(nbOfTuples-1);
8001 std::vector<DataArrayIdType *> ret;
8004 std::vector<bool> fetchedCells(nbOfCellsCur,false);
8005 std::vector< MCAuto<DataArrayIdType> > ret2;
8007 while(seed<nbOfCellsCur)
8009 mcIdType nbOfPeelPerformed=0;
8010 ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfPeelPerformed));
8011 seed=ToIdType(std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false)));
8013 for(std::vector< MCAuto<DataArrayIdType> >::iterator it=ret2.begin();it!=ret2.end();it++)
8014 ret.push_back((*it).retn());
8019 * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
8020 * newly allocated DataArrayIdType instance with 2 components ready to be interpreted as input of DataArrayIdType::findRangeIdForEachTuple method.
8022 * \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.
8023 * \return a newly allocated DataArrayIdType to be managed by the caller.
8024 * \throw In case of \a code has not the right format (typically of size 3*n)
8026 DataArrayIdType *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<mcIdType>& code)
8028 MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
8029 std::size_t nb=code.size()/3;
8030 if(code.size()%3!=0)
8031 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
8033 mcIdType *retPtr=ret->getPointer();
8034 for(std::size_t i=0;i<nb;i++,retPtr+=2)
8036 retPtr[0]=code[3*i+2];
8037 retPtr[1]=code[3*i+2]+code[3*i+1];
8043 * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
8044 * All cells in \a this are expected to be linear 3D cells.
8045 * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
8046 * It leads to an increase to number of cells.
8047 * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
8048 * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
8049 * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
8051 * \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.
8052 * For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
8053 * \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.
8054 * \param [out] n2oCells - A new instance of DataArrayIdType holding, for each new cell,
8055 * an id of old cell producing it. The caller is to delete this array using
8056 * decrRef() as it is no more needed.
8057 * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
8059 * \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
8060 * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
8062 * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
8063 * \throw If \a this is not fully constituted with linear 3D cells.
8064 * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
8066 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayIdType *& n2oCells, mcIdType& nbOfAdditionalPoints) const
8068 INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
8069 checkConnectivityFullyDefined();
8070 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8071 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
8072 mcIdType nbOfCells=getNumberOfCells();
8073 mcIdType nbNodes(getNumberOfNodes());
8074 MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
8075 MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(nbOfCells,1);
8076 mcIdType *retPt(ret->getPointer());
8077 MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()); newConn->alloc(0,1);
8078 MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
8079 const mcIdType *oldc(_nodal_connec->begin());
8080 const mcIdType *oldci(_nodal_connec_index->begin());
8081 const double *coords(_coords->begin());
8082 for(mcIdType i=0;i<nbOfCells;i++,oldci++,retPt++)
8084 std::vector<mcIdType> a; std::vector<double> b;
8085 INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
8086 std::size_t nbOfTet(a.size()/4); *retPt=ToIdType(nbOfTet);
8087 const mcIdType *aa(&a[0]);
8090 for(std::vector<mcIdType>::iterator it=a.begin();it!=a.end();it++)
8092 *it=(-(*(it))-1+nbNodes);
8093 addPts->insertAtTheEnd(b.begin(),b.end());
8094 nbNodes+=ToIdType(b.size()/3);
8096 for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
8097 newConn->insertAtTheEnd(aa,aa+4);
8099 if(!addPts->empty())
8101 addPts->rearrange(3);
8102 nbOfAdditionalPoints=addPts->getNumberOfTuples();
8103 addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
8104 ret0->setCoords(addPts);
8108 nbOfAdditionalPoints=0;
8109 ret0->setCoords(getCoords());
8111 ret0->setNodalConnectivity(newConn);
8113 ret->computeOffsetsFull();
8114 n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
8118 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
8119 _own_cell(true),_cell_id(-1),_nb_cell(0)
8124 _nb_cell=mesh->getNumberOfCells();
8128 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
8136 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_cell(itc),
8137 _own_cell(false),_cell_id(bg-1),
8144 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
8147 if(_cell_id<_nb_cell)
8156 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
8162 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
8164 return new MEDCouplingUMeshCellByTypeIterator(_mesh);
8167 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
8173 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh, INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_type(type),
8181 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
8187 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
8192 mcIdType MEDCouplingUMeshCellEntry::getNumberOfElems() const
8197 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
8199 return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
8202 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
8207 _nb_cell=mesh->getNumberOfCells();
8211 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
8218 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
8220 const mcIdType *c=_mesh->getNodalConnectivity()->begin();
8221 const mcIdType *ci=_mesh->getNodalConnectivityIndex()->begin();
8222 if(_cell_id<_nb_cell)
8224 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
8225 mcIdType nbOfElems=ToIdType(std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type))));
8226 mcIdType startId=_cell_id;
8227 _cell_id+=nbOfElems;
8228 return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
8234 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
8238 _conn=mesh->getNodalConnectivity()->getPointer();
8239 _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
8243 void MEDCouplingUMeshCell::next()
8245 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8250 _conn_lgth=_conn_indx[1]-_conn_indx[0];
8253 std::string MEDCouplingUMeshCell::repr() const
8255 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8257 std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
8259 std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<mcIdType>(oss," "));
8263 return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
8266 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
8268 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8269 return (INTERP_KERNEL::NormalizedCellType)_conn[0];
8271 return INTERP_KERNEL::NORM_ERROR;
8274 const mcIdType *MEDCouplingUMeshCell::getAllConn(mcIdType& lgth) const
8277 if(_conn_lgth!=NOTICABLE_FIRST_VAL)