1 // Copyright (C) 2007-2015 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 (CEA/DEN)
21 #include "MEDCouplingUMesh.hxx"
22 #include "MEDCoupling1GTUMesh.hxx"
23 #include "MEDCouplingMemArray.txx"
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"
52 using namespace MEDCoupling;
54 double MEDCouplingUMesh::EPS_FOR_POLYH_ORIENTATION=1.e-14;
57 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_HEXA20, INTERP_KERNEL::NORM_HEXA27, INTERP_KERNEL::NORM_POLYHED };
60 MEDCouplingUMesh *MEDCouplingUMesh::New()
62 return new MEDCouplingUMesh;
65 MEDCouplingUMesh *MEDCouplingUMesh::New(const std::string& meshName, int meshDim)
67 MEDCouplingUMesh *ret=new MEDCouplingUMesh;
68 ret->setName(meshName);
69 ret->setMeshDimension(meshDim);
74 * Returns a new MEDCouplingUMesh which is a full copy of \a this one. No data is shared
75 * between \a this and the new mesh.
76 * \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
77 * delete this mesh using decrRef() as it is no more needed.
79 MEDCouplingUMesh *MEDCouplingUMesh::deepCopy() const
86 * Returns a new MEDCouplingUMesh which is a copy of \a this one.
87 * \param [in] recDeepCpy - if \a true, the copy is deep, else all data arrays of \a
88 * this mesh are shared by the new mesh.
89 * \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
90 * delete this mesh using decrRef() as it is no more needed.
92 MEDCouplingUMesh *MEDCouplingUMesh::clone(bool recDeepCpy) const
94 return new MEDCouplingUMesh(*this,recDeepCpy);
98 * This method behaves mostly like MEDCouplingUMesh::deepCopy method, except that only nodal connectivity arrays are deeply copied.
99 * The coordinates are shared between \a this and the returned instance.
101 * \return MEDCouplingUMesh * - A new object instance holding the copy of \a this (deep for connectivity, shallow for coordiantes)
102 * \sa MEDCouplingUMesh::deepCopy
104 MEDCouplingUMesh *MEDCouplingUMesh::deepCopyConnectivityOnly() const
106 checkConnectivityFullyDefined();
107 MCAuto<MEDCouplingUMesh> ret=clone(false);
108 MCAuto<DataArrayInt> c(getNodalConnectivity()->deepCopy()),ci(getNodalConnectivityIndex()->deepCopy());
109 ret->setConnectivity(c,ci);
113 void MEDCouplingUMesh::shallowCopyConnectivityFrom(const MEDCouplingPointSet *other)
116 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is null !");
117 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
119 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is not an MEDCouplingUMesh instance !");
120 MEDCouplingUMesh *otherC2=const_cast<MEDCouplingUMesh *>(otherC);//sorry :(
121 setConnectivity(otherC2->getNodalConnectivity(),otherC2->getNodalConnectivityIndex(),true);
124 std::size_t MEDCouplingUMesh::getHeapMemorySizeWithoutChildren() const
126 std::size_t ret(MEDCouplingPointSet::getHeapMemorySizeWithoutChildren());
130 std::vector<const BigMemoryObject *> MEDCouplingUMesh::getDirectChildrenWithNull() const
132 std::vector<const BigMemoryObject *> ret(MEDCouplingPointSet::getDirectChildrenWithNull());
133 ret.push_back(_nodal_connec);
134 ret.push_back(_nodal_connec_index);
138 void MEDCouplingUMesh::updateTime() const
140 MEDCouplingPointSet::updateTime();
143 updateTimeWith(*_nodal_connec);
145 if(_nodal_connec_index)
147 updateTimeWith(*_nodal_connec_index);
151 MEDCouplingUMesh::MEDCouplingUMesh():_mesh_dim(-2),_nodal_connec(0),_nodal_connec_index(0)
156 * Checks if \a this mesh is well defined. If no exception is thrown by this method,
157 * then \a this mesh is most probably is writable, exchangeable and available for most
158 * of algorithms. When a mesh is constructed from scratch, it is a good habit to call
159 * this method to check that all is in order with \a this mesh.
160 * \throw If the mesh dimension is not set.
161 * \throw If the coordinates array is not set (if mesh dimension != -1 ).
162 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
163 * \throw If the connectivity data array has more than one component.
164 * \throw If the connectivity data array has a named component.
165 * \throw If the connectivity index data array has more than one component.
166 * \throw If the connectivity index data array has a named component.
168 void MEDCouplingUMesh::checkConsistencyLight() const
171 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
173 MEDCouplingPointSet::checkConsistencyLight();
174 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
176 if((int)INTERP_KERNEL::CellModel::GetCellModel(*iter).getDimension()!=_mesh_dim)
178 std::ostringstream message;
179 message << "Mesh invalid because dimension is " << _mesh_dim << " and there is presence of cell(s) with type " << (*iter);
180 throw INTERP_KERNEL::Exception(message.str().c_str());
185 if(_nodal_connec->getNumberOfComponents()!=1)
186 throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to be with number of components set to one !");
187 if(_nodal_connec->getInfoOnComponent(0)!="")
188 throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to have no info on its single component !");
192 throw INTERP_KERNEL::Exception("Nodal connectivity array is not defined !");
193 if(_nodal_connec_index)
195 if(_nodal_connec_index->getNumberOfComponents()!=1)
196 throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to be with number of components set to one !");
197 if(_nodal_connec_index->getInfoOnComponent(0)!="")
198 throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to have no info on its single component !");
202 throw INTERP_KERNEL::Exception("Nodal connectivity index array is not defined !");
206 * Checks if \a this mesh is well defined. If no exception is thrown by this method,
207 * then \a this mesh is most probably is writable, exchangeable and available for all
208 * algorithms. <br> In addition to the checks performed by checkConsistencyLight(), this
209 * method thoroughly checks the nodal connectivity.
210 * \param [in] eps - a not used parameter.
211 * \throw If the mesh dimension is not set.
212 * \throw If the coordinates array is not set (if mesh dimension != -1 ).
213 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
214 * \throw If the connectivity data array has more than one component.
215 * \throw If the connectivity data array has a named component.
216 * \throw If the connectivity index data array has more than one component.
217 * \throw If the connectivity index data array has a named component.
218 * \throw If number of nodes defining an element does not correspond to the type of element.
219 * \throw If the nodal connectivity includes an invalid node id.
221 void MEDCouplingUMesh::checkConsistency(double eps) const
223 checkConsistencyLight();
226 int meshDim=getMeshDimension();
227 int nbOfNodes=getNumberOfNodes();
228 int nbOfCells=getNumberOfCells();
229 const int *ptr=_nodal_connec->getConstPointer();
230 const int *ptrI=_nodal_connec_index->getConstPointer();
231 for(int i=0;i<nbOfCells;i++)
233 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)ptr[ptrI[i]]);
234 if((int)cm.getDimension()!=meshDim)
236 std::ostringstream oss;
237 oss << "MEDCouplingUMesh::checkConsistency : cell << #" << i<< " with type Type " << cm.getRepr() << " in 'this' whereas meshdim == " << meshDim << " !";
238 throw INTERP_KERNEL::Exception(oss.str().c_str());
240 int nbOfNodesInCell=ptrI[i+1]-ptrI[i]-1;
242 if(nbOfNodesInCell!=(int)cm.getNumberOfNodes())
244 std::ostringstream oss;
245 oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with static Type '" << cm.getRepr() << "' has " << cm.getNumberOfNodes();
246 oss << " nodes whereas in connectivity there is " << nbOfNodesInCell << " nodes ! Looks very bad !";
247 throw INTERP_KERNEL::Exception(oss.str().c_str());
249 if(cm.isQuadratic() && cm.isDynamic() && meshDim == 2)
250 if (nbOfNodesInCell % 2 || nbOfNodesInCell < 4)
252 std::ostringstream oss;
253 oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with quadratic type '" << cm.getRepr() << "' has " << nbOfNodesInCell;
254 oss << " nodes. This should be even, and greater or equal than 4!! Looks very bad!";
255 throw INTERP_KERNEL::Exception(oss.str().c_str());
257 for(const int *w=ptr+ptrI[i]+1;w!=ptr+ptrI[i+1];w++)
262 if(nodeId>=nbOfNodes)
264 std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " whereas there are only " << nbOfNodes << " nodes in the mesh !";
265 throw INTERP_KERNEL::Exception(oss.str().c_str());
270 std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " in connectivity ! sounds bad !";
271 throw INTERP_KERNEL::Exception(oss.str().c_str());
275 if((INTERP_KERNEL::NormalizedCellType)(ptr[ptrI[i]])!=INTERP_KERNEL::NORM_POLYHED)
277 std::ostringstream oss; oss << "Cell #" << i << " is built with node #-1 in connectivity ! sounds bad !";
278 throw INTERP_KERNEL::Exception(oss.str().c_str());
286 * Sets dimension of \a this mesh. The mesh dimension in general depends on types of
287 * elements contained in the mesh. For more info on the mesh dimension see
288 * \ref MEDCouplingUMeshPage.
289 * \param [in] meshDim - a new mesh dimension.
290 * \throw If \a meshDim is invalid. A valid range is <em> -1 <= meshDim <= 3</em>.
292 void MEDCouplingUMesh::setMeshDimension(int meshDim)
294 if(meshDim<-1 || meshDim>3)
295 throw INTERP_KERNEL::Exception("Invalid meshDim specified ! Must be greater or equal to -1 and lower or equal to 3 !");
301 * Allocates memory to store an estimation of the given number of cells. The closer is the estimation to the number of cells effectively inserted,
302 * the less will the library need to reallocate memory. If the number of cells to be inserted is not known simply put 0 to this parameter.
303 * If a nodal connectivity previouly existed before the call of this method, it will be reset.
305 * \param [in] nbOfCells - estimation of the number of cell \a this mesh will contain.
307 * \if ENABLE_EXAMPLES
308 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
309 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
312 void MEDCouplingUMesh::allocateCells(int nbOfCells)
315 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::allocateCells : the input number of cells should be >= 0 !");
316 if(_nodal_connec_index)
318 _nodal_connec_index->decrRef();
322 _nodal_connec->decrRef();
324 _nodal_connec_index=DataArrayInt::New();
325 _nodal_connec_index->reserve(nbOfCells+1);
326 _nodal_connec_index->pushBackSilent(0);
327 _nodal_connec=DataArrayInt::New();
328 _nodal_connec->reserve(2*nbOfCells);
334 * Appends a cell to the connectivity array. For deeper understanding what is
335 * happening see \ref MEDCouplingUMeshNodalConnectivity.
336 * \param [in] type - type of cell to add.
337 * \param [in] size - number of nodes constituting this cell.
338 * \param [in] nodalConnOfCell - the connectivity of the cell to add.
340 * \if ENABLE_EXAMPLES
341 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
342 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
345 void MEDCouplingUMesh::insertNextCell(INTERP_KERNEL::NormalizedCellType type, int size, const int *nodalConnOfCell)
347 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
348 if(_nodal_connec_index==0)
349 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::insertNextCell : nodal connectivity not set ! invoke allocateCells before calling insertNextCell !");
350 if((int)cm.getDimension()==_mesh_dim)
353 if(size!=(int)cm.getNumberOfNodes())
355 std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : Trying to push a " << cm.getRepr() << " cell with a size of " << size;
356 oss << " ! Expecting " << cm.getNumberOfNodes() << " !";
357 throw INTERP_KERNEL::Exception(oss.str().c_str());
359 int idx=_nodal_connec_index->back();
361 _nodal_connec_index->pushBackSilent(val);
362 _nodal_connec->writeOnPlace(idx,type,nodalConnOfCell,size);
367 std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : cell type " << cm.getRepr() << " has a dimension " << cm.getDimension();
368 oss << " whereas Mesh Dimension of current UMesh instance is set to " << _mesh_dim << " ! Please invoke \"setMeshDimension\" method before or invoke ";
369 oss << "\"MEDCouplingUMesh::New\" static method with 2 parameters name and meshDimension !";
370 throw INTERP_KERNEL::Exception(oss.str().c_str());
375 * Compacts data arrays to release unused memory. This method is to be called after
376 * finishing cell insertion using \a this->insertNextCell().
378 * \if ENABLE_EXAMPLES
379 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
380 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
383 void MEDCouplingUMesh::finishInsertingCells()
385 _nodal_connec->pack();
386 _nodal_connec_index->pack();
387 _nodal_connec->declareAsNew();
388 _nodal_connec_index->declareAsNew();
393 * Entry point for iteration over cells of this. Warning the returned cell iterator should be deallocated.
394 * Useful for python users.
396 MEDCouplingUMeshCellIterator *MEDCouplingUMesh::cellIterator()
398 return new MEDCouplingUMeshCellIterator(this);
402 * Entry point for iteration over cells groups geo types per geotypes. Warning the returned cell iterator should be deallocated.
403 * If \a this is not so that that cells are grouped by geo types this method will throw an exception.
404 * In this case MEDCouplingUMesh::sortCellsInMEDFileFrmt or MEDCouplingUMesh::rearrange2ConsecutiveCellTypes methods for example can be called before invoking this method.
405 * Useful for python users.
407 MEDCouplingUMeshCellByTypeEntry *MEDCouplingUMesh::cellsByType()
409 if(!checkConsecutiveCellTypes())
410 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::cellsByType : this mesh is not sorted by type !");
411 return new MEDCouplingUMeshCellByTypeEntry(this);
415 * Returns a set of all cell types available in \a this mesh.
416 * \return std::set<INTERP_KERNEL::NormalizedCellType> - the set of cell types.
417 * \warning this method does not throw any exception even if \a this is not defined.
418 * \sa MEDCouplingUMesh::getAllGeoTypesSorted
420 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypes() const
426 * This method returns the sorted list of geometric types in \a this.
427 * 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
428 * having the same geometric type. So a same geometric type can appear more than once if the cells are not sorted per geometric type.
430 * \throw if connectivity in \a this is not correctly defined.
432 * \sa MEDCouplingMesh::getAllGeoTypes
434 std::vector<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypesSorted() const
436 std::vector<INTERP_KERNEL::NormalizedCellType> ret;
437 checkConnectivityFullyDefined();
438 int nbOfCells(getNumberOfCells());
441 if(getNodalConnectivityArrayLen()<1)
442 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAllGeoTypesSorted : the connectivity in this seems invalid !");
443 const int *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin());
444 ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci++]);
445 for(int i=1;i<nbOfCells;i++,ci++)
446 if(ret.back()!=((INTERP_KERNEL::NormalizedCellType)c[*ci]))
447 ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci]);
452 * This method is a method that compares \a this and \a other.
453 * This method compares \b all attributes, even names and component names.
455 bool MEDCouplingUMesh::isEqualIfNotWhy(const MEDCouplingMesh *other, double prec, std::string& reason) const
458 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isEqualIfNotWhy : input other pointer is null !");
459 std::ostringstream oss; oss.precision(15);
460 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
463 reason="mesh given in input is not castable in MEDCouplingUMesh !";
466 if(!MEDCouplingPointSet::isEqualIfNotWhy(other,prec,reason))
468 if(_mesh_dim!=otherC->_mesh_dim)
470 oss << "umesh dimension mismatch : this mesh dimension=" << _mesh_dim << " other mesh dimension=" << otherC->_mesh_dim;
474 if(_types!=otherC->_types)
476 oss << "umesh geometric type mismatch :\nThis geometric types are :";
477 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
478 { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
479 oss << "\nOther geometric types are :";
480 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=otherC->_types.begin();iter!=otherC->_types.end();iter++)
481 { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
485 if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
486 if(_nodal_connec==0 || otherC->_nodal_connec==0)
488 reason="Only one UMesh between the two this and other has its nodal connectivity DataArrayInt defined !";
491 if(_nodal_connec!=otherC->_nodal_connec)
492 if(!_nodal_connec->isEqualIfNotWhy(*otherC->_nodal_connec,reason))
494 reason.insert(0,"Nodal connectivity DataArrayInt differ : ");
497 if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
498 if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
500 reason="Only one UMesh between the two this and other has its nodal connectivity index DataArrayInt defined !";
503 if(_nodal_connec_index!=otherC->_nodal_connec_index)
504 if(!_nodal_connec_index->isEqualIfNotWhy(*otherC->_nodal_connec_index,reason))
506 reason.insert(0,"Nodal connectivity index DataArrayInt differ : ");
513 * Checks if data arrays of this mesh (node coordinates, nodal
514 * connectivity of cells, etc) of two meshes are same. Textual data like name etc. are
516 * \param [in] other - the mesh to compare with.
517 * \param [in] prec - precision value used to compare node coordinates.
518 * \return bool - \a true if the two meshes are same.
520 bool MEDCouplingUMesh::isEqualWithoutConsideringStr(const MEDCouplingMesh *other, double prec) const
522 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
525 if(!MEDCouplingPointSet::isEqualWithoutConsideringStr(other,prec))
527 if(_mesh_dim!=otherC->_mesh_dim)
529 if(_types!=otherC->_types)
531 if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
532 if(_nodal_connec==0 || otherC->_nodal_connec==0)
534 if(_nodal_connec!=otherC->_nodal_connec)
535 if(!_nodal_connec->isEqualWithoutConsideringStr(*otherC->_nodal_connec))
537 if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
538 if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
540 if(_nodal_connec_index!=otherC->_nodal_connec_index)
541 if(!_nodal_connec_index->isEqualWithoutConsideringStr(*otherC->_nodal_connec_index))
547 * Checks if \a this and \a other meshes are geometrically equivalent with high
548 * probability, else an exception is thrown. The meshes are considered equivalent if
549 * (1) meshes contain the same number of nodes and the same number of elements of the
550 * same types (2) three cells of the two meshes (first, last and middle) are based
551 * on coincident nodes (with a specified precision).
552 * \param [in] other - the mesh to compare with.
553 * \param [in] prec - the precision used to compare nodes of the two meshes.
554 * \throw If the two meshes do not match.
556 void MEDCouplingUMesh::checkFastEquivalWith(const MEDCouplingMesh *other, double prec) const
558 MEDCouplingPointSet::checkFastEquivalWith(other,prec);
559 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
561 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkFastEquivalWith : Two meshes are not not unstructured !");
565 * Returns the reverse nodal connectivity. The reverse nodal connectivity enumerates
566 * cells each node belongs to.
567 * \warning For speed reasons, this method does not check if node ids in the nodal
568 * connectivity correspond to the size of node coordinates array.
569 * \param [in,out] revNodal - an array holding ids of cells sharing each node.
570 * \param [in,out] revNodalIndx - an array, of length \a this->getNumberOfNodes() + 1,
571 * dividing cell ids in \a revNodal into groups each referring to one
572 * node. Its every element (except the last one) is an index pointing to the
573 * first id of a group of cells. For example cells sharing the node #1 are
574 * described by following range of indices:
575 * [ \a revNodalIndx[1], \a revNodalIndx[2] ) and the cell ids are
576 * \a revNodal[ \a revNodalIndx[1] ], \a revNodal[ \a revNodalIndx[1] + 1], ...
577 * Number of cells sharing the *i*-th node is
578 * \a revNodalIndx[ *i*+1 ] - \a revNodalIndx[ *i* ].
579 * \throw If the coordinates array is not set.
580 * \throw If the nodal connectivity of cells is not defined.
582 * \if ENABLE_EXAMPLES
583 * \ref cpp_mcumesh_getReverseNodalConnectivity "Here is a C++ example".<br>
584 * \ref py_mcumesh_getReverseNodalConnectivity "Here is a Python example".
587 void MEDCouplingUMesh::getReverseNodalConnectivity(DataArrayInt *revNodal, DataArrayInt *revNodalIndx) const
590 int nbOfNodes=getNumberOfNodes();
591 int *revNodalIndxPtr=(int *)malloc((nbOfNodes+1)*sizeof(int));
592 revNodalIndx->useArray(revNodalIndxPtr,true,C_DEALLOC,nbOfNodes+1,1);
593 std::fill(revNodalIndxPtr,revNodalIndxPtr+nbOfNodes+1,0);
594 const int *conn=_nodal_connec->getConstPointer();
595 const int *connIndex=_nodal_connec_index->getConstPointer();
596 int nbOfCells=getNumberOfCells();
597 int nbOfEltsInRevNodal=0;
598 for(int eltId=0;eltId<nbOfCells;eltId++)
600 const int *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
601 const int *endNdlConnOfCurCell=conn+connIndex[eltId+1];
602 for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
603 if(*iter>=0)//for polyhedrons
605 nbOfEltsInRevNodal++;
606 revNodalIndxPtr[(*iter)+1]++;
609 std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<int>());
610 int *revNodalPtr=(int *)malloc((nbOfEltsInRevNodal)*sizeof(int));
611 revNodal->useArray(revNodalPtr,true,C_DEALLOC,nbOfEltsInRevNodal,1);
612 std::fill(revNodalPtr,revNodalPtr+nbOfEltsInRevNodal,-1);
613 for(int eltId=0;eltId<nbOfCells;eltId++)
615 const int *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
616 const int *endNdlConnOfCurCell=conn+connIndex[eltId+1];
617 for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
618 if(*iter>=0)//for polyhedrons
619 *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind2nd(std::equal_to<int>(),-1))=eltId;
625 int MEDCouplingFastNbrer(int id, unsigned nb, const INTERP_KERNEL::CellModel& cm, bool compute, const int *conn1, const int *conn2)
630 int MEDCouplingOrientationSensitiveNbrer(int id, unsigned nb, const INTERP_KERNEL::CellModel& cm, bool compute, const int *conn1, const int *conn2)
636 if(cm.getOrientationStatus(nb,conn1,conn2))
643 class MinusOneSonsGenerator
646 MinusOneSonsGenerator(const INTERP_KERNEL::CellModel& cm):_cm(cm) { }
647 unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfSons2(conn,lgth); }
648 unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillSonCellNodalConnectivity2(sonId,nodalConn,lgth,sonNodalConn,typeOfSon); }
649 static const int DELTA=1;
651 const INTERP_KERNEL::CellModel& _cm;
654 class MinusOneSonsGeneratorBiQuadratic
657 MinusOneSonsGeneratorBiQuadratic(const INTERP_KERNEL::CellModel& cm):_cm(cm) { }
658 unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfSons2(conn,lgth); }
659 unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillSonCellNodalConnectivity4(sonId,nodalConn,lgth,sonNodalConn,typeOfSon); }
660 static const int DELTA=1;
662 const INTERP_KERNEL::CellModel& _cm;
665 class MinusTwoSonsGenerator
668 MinusTwoSonsGenerator(const INTERP_KERNEL::CellModel& cm):_cm(cm) { }
669 unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfEdgesIn3D(conn,lgth); }
670 unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillSonEdgesNodalConnectivity3D(sonId,nodalConn,lgth,sonNodalConn,typeOfSon); }
671 static const int DELTA=2;
673 const INTERP_KERNEL::CellModel& _cm;
679 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
680 * this->getMeshDimension(), that bound cells of \a this mesh. In addition arrays
681 * describing correspondence between cells of \a this and the result meshes are
682 * returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending connectivity,
683 * i.e. enumerate cells of the result mesh bounding each cell of \a this mesh. The
684 * arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
685 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
686 * \warning For speed reasons, this method does not check if node ids in the nodal
687 * connectivity correspond to the size of node coordinates array.
688 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
689 * to write this mesh to the MED file, its cells must be sorted using
690 * sortCellsInMEDFileFrmt().
691 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
692 * each cell of \a this mesh.
693 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
694 * dividing cell ids in \a desc into groups each referring to one
695 * cell of \a this mesh. Its every element (except the last one) is an index
696 * pointing to the first id of a group of cells. For example cells of the
697 * result mesh bounding the cell #1 of \a this mesh are described by following
699 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
700 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
701 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
702 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
703 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
704 * by each cell of the result mesh.
705 * \param [in,out] revDescIndx - the array, of length one more than number of cells
706 * in the result mesh,
707 * dividing cell ids in \a revDesc into groups each referring to one
708 * cell of the result mesh the same way as \a descIndx divides \a desc.
709 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
710 * delete this mesh using decrRef() as it is no more needed.
711 * \throw If the coordinates array is not set.
712 * \throw If the nodal connectivity of cells is node defined.
713 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
714 * revDescIndx == NULL.
716 * \if ENABLE_EXAMPLES
717 * \ref cpp_mcumesh_buildDescendingConnectivity "Here is a C++ example".<br>
718 * \ref py_mcumesh_buildDescendingConnectivity "Here is a Python example".
720 * \sa buildDescendingConnectivity2()
722 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
724 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
728 * \a this has to have a mesh dimension equal to 3. If it is not the case an INTERP_KERNEL::Exception will be thrown.
729 * This behaves exactly as MEDCouplingUMesh::buildDescendingConnectivity does except that this method compute directly the transition from mesh dimension 3 to sub edges (dimension 1)
730 * in one shot. That is to say that this method is equivalent to 2 successive calls to MEDCouplingUMesh::buildDescendingConnectivity.
731 * This method returns 4 arrays and a mesh as MEDCouplingUMesh::buildDescendingConnectivity does.
732 * \sa MEDCouplingUMesh::buildDescendingConnectivity
734 MEDCouplingUMesh *MEDCouplingUMesh::explode3DMeshTo1D(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
737 if(getMeshDimension()!=3)
738 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explode3DMeshTo1D : This has to have a mesh dimension to 3 !");
739 return buildDescendingConnectivityGen<MinusTwoSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
743 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
744 * this->getMeshDimension(), that bound cells of \a this mesh. In
745 * addition arrays describing correspondence between cells of \a this and the result
746 * meshes are returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending
747 * connectivity, i.e. enumerate cells of the result mesh bounding each cell of \a this
748 * mesh. This method differs from buildDescendingConnectivity() in that apart
749 * from cell ids, \a desc returns mutual orientation of cells in \a this and the
750 * result meshes. So a positive id means that order of nodes in corresponding cells
751 * of two meshes is same, and a negative id means a reverse order of nodes. Since a
752 * cell with id #0 can't be negative, the array \a desc returns ids in FORTRAN mode,
753 * i.e. cell ids are one-based.
754 * Arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
755 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
756 * \warning For speed reasons, this method does not check if node ids in the nodal
757 * connectivity correspond to the size of node coordinates array.
758 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
759 * to write this mesh to the MED file, its cells must be sorted using
760 * sortCellsInMEDFileFrmt().
761 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
762 * each cell of \a this mesh.
763 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
764 * dividing cell ids in \a desc into groups each referring to one
765 * cell of \a this mesh. Its every element (except the last one) is an index
766 * pointing to the first id of a group of cells. For example cells of the
767 * result mesh bounding the cell #1 of \a this mesh are described by following
769 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
770 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
771 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
772 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
773 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
774 * by each cell of the result mesh.
775 * \param [in,out] revDescIndx - the array, of length one more than number of cells
776 * in the result mesh,
777 * dividing cell ids in \a revDesc into groups each referring to one
778 * cell of the result mesh the same way as \a descIndx divides \a desc.
779 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This result mesh
780 * shares the node coordinates array with \a this mesh. The caller is to
781 * delete this mesh using decrRef() as it is no more needed.
782 * \throw If the coordinates array is not set.
783 * \throw If the nodal connectivity of cells is node defined.
784 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
785 * revDescIndx == NULL.
787 * \if ENABLE_EXAMPLES
788 * \ref cpp_mcumesh_buildDescendingConnectivity2 "Here is a C++ example".<br>
789 * \ref py_mcumesh_buildDescendingConnectivity2 "Here is a Python example".
791 * \sa buildDescendingConnectivity()
793 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
795 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingOrientationSensitiveNbrer);
799 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
800 * For speed reasons no check of this will be done. This method calls
801 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
802 * This method lists cell by cell in \b this which are its neighbors. To compute the result
803 * only connectivities are considered.
804 * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
805 * The format of return is hence \ref numbering-indirect.
807 * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly
808 * allocated and should be dealt by the caller. \b neighborsIndx 2nd output
809 * parameter allows to select the right part in this array (\ref numbering-indirect). The number of tuples
810 * is equal to the last values in \b neighborsIndx.
811 * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be
812 * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
814 void MEDCouplingUMesh::computeNeighborsOfCells(DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx) const
816 MCAuto<DataArrayInt> desc=DataArrayInt::New();
817 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
818 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
819 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
820 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
822 ComputeNeighborsOfCellsAdv(desc,descIndx,revDesc,revDescIndx,neighbors,neighborsIndx);
826 * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm
827 * of MEDCouplingUMesh::computeNeighborsOfCells.
828 * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is
829 * typically the case to extract a set a neighbours,
830 * excluding a set of meshdim-1 cells in input descending connectivity.
831 * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx (\ref numbering-indirect) input params are
832 * the result of MEDCouplingUMesh::buildDescendingConnectivity.
833 * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities
835 * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
837 * \param [in] desc descending connectivity array.
838 * \param [in] descIndx descending connectivity index array used to walk through \b desc (\ref numbering-indirect).
839 * \param [in] revDesc reverse descending connectivity array.
840 * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc (\ref numbering-indirect).
841 * \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
842 * parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
843 * \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.
845 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayInt *desc, const DataArrayInt *descIndx, const DataArrayInt *revDesc, const DataArrayInt *revDescIndx,
846 DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx)
848 if(!desc || !descIndx || !revDesc || !revDescIndx)
849 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
850 const int *descPtr=desc->getConstPointer();
851 const int *descIPtr=descIndx->getConstPointer();
852 const int *revDescPtr=revDesc->getConstPointer();
853 const int *revDescIPtr=revDescIndx->getConstPointer();
855 int nbCells=descIndx->getNumberOfTuples()-1;
856 MCAuto<DataArrayInt> out0=DataArrayInt::New();
857 MCAuto<DataArrayInt> out1=DataArrayInt::New(); out1->alloc(nbCells+1,1);
858 int *out1Ptr=out1->getPointer();
860 out0->reserve(desc->getNumberOfTuples());
861 for(int i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
863 for(const int *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
865 std::set<int> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
867 out0->insertAtTheEnd(s.begin(),s.end());
869 *out1Ptr=out0->getNumberOfTuples();
871 neighbors=out0.retn();
872 neighborsIndx=out1.retn();
876 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
877 * For speed reasons no check of this will be done. This method calls
878 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
879 * This method lists node by node in \b this which are its neighbors. To compute the result
880 * only connectivities are considered.
881 * The neighbor nodes of node having id 'nodeId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
883 * \param [out] neighbors is an array storing all the neighbors of all nodes in \b this. This array
884 * is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
885 * parameter allows to select the right part in this array (\ref numbering-indirect).
886 * The number of tuples is equal to the last values in \b neighborsIndx.
887 * \param [out] neighborsIdx is an array of size this->getNumberOfCells()+1 newly allocated and should
888 * be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
890 void MEDCouplingUMesh::computeNeighborsOfNodes(DataArrayInt *&neighbors, DataArrayInt *&neighborsIdx) const
893 int mdim(getMeshDimension()),nbNodes(getNumberOfNodes());
894 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descIndx(DataArrayInt::New()),revDesc(DataArrayInt::New()),revDescIndx(DataArrayInt::New());
895 MCAuto<MEDCouplingUMesh> mesh1D;
900 mesh1D=explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx);
905 mesh1D=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
910 mesh1D=const_cast<MEDCouplingUMesh *>(this);
916 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2,1] !");
919 desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=0; revDescIndx=0;
920 mesh1D->getReverseNodalConnectivity(desc,descIndx);
921 MCAuto<DataArrayInt> ret0(DataArrayInt::New());
922 ret0->alloc(desc->getNumberOfTuples(),1);
923 int *r0Pt(ret0->getPointer());
924 const int *c1DPtr(mesh1D->getNodalConnectivity()->begin()),*rn(desc->begin()),*rni(descIndx->begin());
925 for(int i=0;i<nbNodes;i++,rni++)
927 for(const int *oneDCellIt=rn+rni[0];oneDCellIt!=rn+rni[1];oneDCellIt++)
928 *r0Pt++=c1DPtr[3*(*oneDCellIt)+1]==i?c1DPtr[3*(*oneDCellIt)+2]:c1DPtr[3*(*oneDCellIt)+1];
930 neighbors=ret0.retn();
931 neighborsIdx=descIndx.retn();
937 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
938 * For speed reasons no check of this will be done.
940 template<class SonsGenerator>
941 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivityGen(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx, DimM1DescNbrer nbrer) const
943 if(!desc || !descIndx || !revDesc || !revDescIndx)
944 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildDescendingConnectivityGen : present of a null pointer in input !");
945 checkConnectivityFullyDefined();
946 int nbOfCells=getNumberOfCells();
947 int nbOfNodes=getNumberOfNodes();
948 MCAuto<DataArrayInt> revNodalIndx=DataArrayInt::New(); revNodalIndx->alloc(nbOfNodes+1,1); revNodalIndx->fillWithZero();
949 int *revNodalIndxPtr=revNodalIndx->getPointer();
950 const int *conn=_nodal_connec->getConstPointer();
951 const int *connIndex=_nodal_connec_index->getConstPointer();
952 std::string name="Mesh constituent of "; name+=getName();
953 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(name,getMeshDimension()-SonsGenerator::DELTA);
954 ret->setCoords(getCoords());
955 ret->allocateCells(2*nbOfCells);
956 descIndx->alloc(nbOfCells+1,1);
957 MCAuto<DataArrayInt> revDesc2(DataArrayInt::New()); revDesc2->reserve(2*nbOfCells);
958 int *descIndxPtr=descIndx->getPointer(); *descIndxPtr++=0;
959 for(int eltId=0;eltId<nbOfCells;eltId++,descIndxPtr++)
961 int pos=connIndex[eltId];
962 int posP1=connIndex[eltId+1];
963 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[pos]);
964 SonsGenerator sg(cm);
965 unsigned nbOfSons=sg.getNumberOfSons2(conn+pos+1,posP1-pos-1);
966 INTERP_KERNEL::AutoPtr<int> tmp=new int[posP1-pos];
967 for(unsigned i=0;i<nbOfSons;i++)
969 INTERP_KERNEL::NormalizedCellType cmsId;
970 unsigned nbOfNodesSon=sg.fillSonCellNodalConnectivity2(i,conn+pos+1,posP1-pos-1,tmp,cmsId);
971 for(unsigned k=0;k<nbOfNodesSon;k++)
973 revNodalIndxPtr[tmp[k]+1]++;
974 ret->insertNextCell(cmsId,nbOfNodesSon,tmp);
975 revDesc2->pushBackSilent(eltId);
977 descIndxPtr[0]=descIndxPtr[-1]+(int)nbOfSons;
979 int nbOfCellsM1=ret->getNumberOfCells();
980 std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<int>());
981 MCAuto<DataArrayInt> revNodal=DataArrayInt::New(); revNodal->alloc(revNodalIndx->back(),1);
982 std::fill(revNodal->getPointer(),revNodal->getPointer()+revNodalIndx->back(),-1);
983 int *revNodalPtr=revNodal->getPointer();
984 const int *connM1=ret->getNodalConnectivity()->getConstPointer();
985 const int *connIndexM1=ret->getNodalConnectivityIndex()->getConstPointer();
986 for(int eltId=0;eltId<nbOfCellsM1;eltId++)
988 const int *strtNdlConnOfCurCell=connM1+connIndexM1[eltId]+1;
989 const int *endNdlConnOfCurCell=connM1+connIndexM1[eltId+1];
990 for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
991 if(*iter>=0)//for polyhedrons
992 *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind2nd(std::equal_to<int>(),-1))=eltId;
995 DataArrayInt *commonCells=0,*commonCellsI=0;
996 FindCommonCellsAlg(3,0,ret->getNodalConnectivity(),ret->getNodalConnectivityIndex(),revNodal,revNodalIndx,commonCells,commonCellsI);
997 MCAuto<DataArrayInt> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
998 const int *commonCellsPtr(commonCells->getConstPointer()),*commonCellsIPtr(commonCellsI->getConstPointer());
999 int newNbOfCellsM1=-1;
1000 MCAuto<DataArrayInt> o2nM1=DataArrayInt::ConvertIndexArrayToO2N(nbOfCellsM1,commonCells->begin(),
1001 commonCellsI->begin(),commonCellsI->end(),newNbOfCellsM1);
1002 std::vector<bool> isImpacted(nbOfCellsM1,false);
1003 for(const int *work=commonCellsI->begin();work!=commonCellsI->end()-1;work++)
1004 for(int work2=work[0];work2!=work[1];work2++)
1005 isImpacted[commonCellsPtr[work2]]=true;
1006 const int *o2nM1Ptr=o2nM1->getConstPointer();
1007 MCAuto<DataArrayInt> n2oM1=o2nM1->invertArrayO2N2N2OBis(newNbOfCellsM1);
1008 const int *n2oM1Ptr=n2oM1->getConstPointer();
1009 MCAuto<MEDCouplingUMesh> ret2=static_cast<MEDCouplingUMesh *>(ret->buildPartOfMySelf(n2oM1->begin(),n2oM1->end(),true));
1010 ret2->copyTinyInfoFrom(this);
1011 desc->alloc(descIndx->back(),1);
1012 int *descPtr=desc->getPointer();
1013 const INTERP_KERNEL::CellModel& cmsDft=INTERP_KERNEL::CellModel::GetCellModel(INTERP_KERNEL::NORM_POINT1);
1014 for(int i=0;i<nbOfCellsM1;i++,descPtr++)
1017 *descPtr=nbrer(o2nM1Ptr[i],0,cmsDft,false,0,0);
1020 if(i!=n2oM1Ptr[o2nM1Ptr[i]])
1022 const INTERP_KERNEL::CellModel& cms=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connM1[connIndexM1[i]]);
1023 *descPtr=nbrer(o2nM1Ptr[i],connIndexM1[i+1]-connIndexM1[i]-1,cms,true,connM1+connIndexM1[n2oM1Ptr[o2nM1Ptr[i]]]+1,connM1+connIndexM1[i]+1);
1026 *descPtr=nbrer(o2nM1Ptr[i],0,cmsDft,false,0,0);
1029 revDesc->reserve(newNbOfCellsM1);
1030 revDescIndx->alloc(newNbOfCellsM1+1,1);
1031 int *revDescIndxPtr=revDescIndx->getPointer(); *revDescIndxPtr++=0;
1032 const int *revDesc2Ptr=revDesc2->getConstPointer();
1033 for(int i=0;i<newNbOfCellsM1;i++,revDescIndxPtr++)
1035 int oldCellIdM1=n2oM1Ptr[i];
1036 if(!isImpacted[oldCellIdM1])
1038 revDesc->pushBackSilent(revDesc2Ptr[oldCellIdM1]);
1039 revDescIndxPtr[0]=revDescIndxPtr[-1]+1;
1043 for(int j=commonCellsIPtr[0];j<commonCellsIPtr[1];j++)
1044 revDesc->pushBackSilent(revDesc2Ptr[commonCellsPtr[j]]);
1045 revDescIndxPtr[0]=revDescIndxPtr[-1]+commonCellsIPtr[1]-commonCellsIPtr[0];
1053 struct MEDCouplingAccVisit
1055 MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1056 int operator()(int val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1057 int _new_nb_of_nodes;
1063 * Converts specified cells to either polygons (if \a this is a 2D mesh) or
1064 * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an
1065 * array of cell ids. Pay attention that after conversion all algorithms work slower
1066 * with \a this mesh than before conversion. <br> If an exception is thrown during the
1067 * conversion due presence of invalid ids in the array of cells to convert, as a
1068 * result \a this mesh contains some already converted elements. In this case the 2D
1069 * mesh remains valid but 3D mesh becomes \b inconsistent!
1070 * \warning This method can significantly modify the order of geometric types in \a this,
1071 * hence, to write this mesh to the MED file, its cells must be sorted using
1072 * sortCellsInMEDFileFrmt().
1073 * \param [in] cellIdsToConvertBg - the array holding ids of cells to convert.
1074 * \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a
1075 * cellIdsToConvertBg.
1076 * \throw If the coordinates array is not set.
1077 * \throw If the nodal connectivity of cells is node defined.
1078 * \throw If dimension of \a this mesh is not either 2 or 3.
1080 * \if ENABLE_EXAMPLES
1081 * \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".<br>
1082 * \ref py_mcumesh_convertToPolyTypes "Here is a Python example".
1085 void MEDCouplingUMesh::convertToPolyTypes(const int *cellIdsToConvertBg, const int *cellIdsToConvertEnd)
1087 checkFullyDefined();
1088 int dim=getMeshDimension();
1090 throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
1091 int nbOfCells(getNumberOfCells());
1094 const int *connIndex=_nodal_connec_index->getConstPointer();
1095 int *conn=_nodal_connec->getPointer();
1096 for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1098 if(*iter>=0 && *iter<nbOfCells)
1100 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
1101 if(!cm.isQuadratic())
1102 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
1104 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
1108 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1109 oss << " in range [0," << nbOfCells << ") !";
1110 throw INTERP_KERNEL::Exception(oss.str().c_str());
1116 int *connIndex(_nodal_connec_index->getPointer());
1117 const int *connOld(_nodal_connec->getConstPointer());
1118 MCAuto<DataArrayInt> connNew(DataArrayInt::New()),connNewI(DataArrayInt::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0);
1119 std::vector<bool> toBeDone(nbOfCells,false);
1120 for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1122 if(*iter>=0 && *iter<nbOfCells)
1123 toBeDone[*iter]=true;
1126 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1127 oss << " in range [0," << nbOfCells << ") !";
1128 throw INTERP_KERNEL::Exception(oss.str().c_str());
1131 for(int cellId=0;cellId<nbOfCells;cellId++)
1133 int pos(connIndex[cellId]),posP1(connIndex[cellId+1]);
1134 int lgthOld(posP1-pos-1);
1135 if(toBeDone[cellId])
1137 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connOld[pos]);
1138 unsigned nbOfFaces(cm.getNumberOfSons2(connOld+pos+1,lgthOld));
1139 int *tmp(new int[nbOfFaces*lgthOld+1]);
1140 int *work=tmp; *work++=INTERP_KERNEL::NORM_POLYHED;
1141 for(unsigned j=0;j<nbOfFaces;j++)
1143 INTERP_KERNEL::NormalizedCellType type;
1144 unsigned offset=cm.fillSonCellNodalConnectivity2(j,connOld+pos+1,lgthOld,work,type);
1148 std::size_t newLgth(std::distance(tmp,work)-1);//-1 for last -1
1149 connNew->pushBackValsSilent(tmp,tmp+newLgth);
1150 connNewI->pushBackSilent(connNewI->back()+(int)newLgth);
1155 connNew->pushBackValsSilent(connOld+pos,connOld+posP1);
1156 connNewI->pushBackSilent(connNewI->back()+posP1-pos);
1159 setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind.
1165 * Converts all cells to either polygons (if \a this is a 2D mesh) or
1166 * polyhedrons (if \a this is a 3D mesh).
1167 * \warning As this method is purely for user-friendliness and no optimization is
1168 * done to avoid construction of a useless vector, this method can be costly
1170 * \throw If the coordinates array is not set.
1171 * \throw If the nodal connectivity of cells is node defined.
1172 * \throw If dimension of \a this mesh is not either 2 or 3.
1174 void MEDCouplingUMesh::convertAllToPoly()
1176 int nbOfCells=getNumberOfCells();
1177 std::vector<int> cellIds(nbOfCells);
1178 for(int i=0;i<nbOfCells;i++)
1180 convertToPolyTypes(&cellIds[0],&cellIds[0]+cellIds.size());
1184 * Fixes nodal connectivity of invalid cells of type NORM_POLYHED. This method
1185 * expects that all NORM_POLYHED cells have connectivity similar to that of prismatic
1186 * volumes like NORM_HEXA8, NORM_PENTA6 etc., i.e. the first half of nodes describes a
1187 * base facet of the volume and the second half of nodes describes an opposite facet
1188 * having the same number of nodes as the base one. This method converts such
1189 * connectivity to a valid polyhedral format where connectivity of each facet is
1190 * explicitly described and connectivity of facets are separated by -1. If \a this mesh
1191 * contains a NORM_POLYHED cell with a valid connectivity, or an invalid connectivity is
1192 * not as expected, an exception is thrown and the mesh remains unchanged. Care of
1193 * a correct orientation of the first facet of a polyhedron, else orientation of a
1194 * corrected cell is reverse.<br>
1195 * This method is useful to build an extruded unstructured mesh with polyhedrons as
1196 * it releases the user from boring description of polyhedra connectivity in the valid
1198 * \throw If \a this->getMeshDimension() != 3.
1199 * \throw If \a this->getSpaceDimension() != 3.
1200 * \throw If the nodal connectivity of cells is not defined.
1201 * \throw If the coordinates array is not set.
1202 * \throw If \a this mesh contains polyhedrons with the valid connectivity.
1203 * \throw If \a this mesh contains polyhedrons with odd number of nodes.
1205 * \if ENABLE_EXAMPLES
1206 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
1207 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
1210 void MEDCouplingUMesh::convertExtrudedPolyhedra()
1212 checkFullyDefined();
1213 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1214 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
1215 int nbOfCells=getNumberOfCells();
1216 MCAuto<DataArrayInt> newCi=DataArrayInt::New();
1217 newCi->alloc(nbOfCells+1,1);
1218 int *newci=newCi->getPointer();
1219 const int *ci=_nodal_connec_index->getConstPointer();
1220 const int *c=_nodal_connec->getConstPointer();
1222 for(int i=0;i<nbOfCells;i++)
1224 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1225 if(type==INTERP_KERNEL::NORM_POLYHED)
1227 if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
1229 std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
1230 throw INTERP_KERNEL::Exception(oss.str().c_str());
1232 std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
1235 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 !";
1236 throw INTERP_KERNEL::Exception(oss.str().c_str());
1239 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)
1242 newci[i+1]=(ci[i+1]-ci[i])+newci[i];
1244 MCAuto<DataArrayInt> newC=DataArrayInt::New();
1245 newC->alloc(newci[nbOfCells],1);
1246 int *newc=newC->getPointer();
1247 for(int i=0;i<nbOfCells;i++)
1249 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1250 if(type==INTERP_KERNEL::NORM_POLYHED)
1252 std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
1253 newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
1255 for(std::size_t j=0;j<n1;j++)
1257 newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
1259 newc[n1+5*j+1]=c[ci[i]+1+j];
1260 newc[n1+5*j+2]=c[ci[i]+1+j+n1];
1261 newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
1262 newc[n1+5*j+4]=c[ci[i]+1+(j+1)%n1];
1267 newc=std::copy(c+ci[i],c+ci[i+1],newc);
1269 _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
1270 _nodal_connec->decrRef(); _nodal_connec=newC.retn();
1275 * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D
1276 * mesh) to cells of classical types. This method is opposite to convertToPolyTypes().
1277 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
1278 * to write this mesh to the MED file, its cells must be sorted using
1279 * sortCellsInMEDFileFrmt().
1280 * \warning Cells (and most notably polyhedrons) must be correctly oriented for this to work
1281 * properly. See orientCorrectlyPolyhedrons() and arePolyhedronsNotCorrectlyOriented().
1282 * \return \c true if at least one cell has been converted, \c false else. In the
1283 * last case the nodal connectivity remains unchanged.
1284 * \throw If the coordinates array is not set.
1285 * \throw If the nodal connectivity of cells is not defined.
1286 * \throw If \a this->getMeshDimension() < 0.
1288 bool MEDCouplingUMesh::unPolyze()
1290 checkFullyDefined();
1291 int mdim=getMeshDimension();
1293 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1296 int nbOfCells=getNumberOfCells();
1299 int initMeshLgth=getNodalConnectivityArrayLen();
1300 int *conn=_nodal_connec->getPointer();
1301 int *index=_nodal_connec_index->getPointer();
1306 for(int i=0;i<nbOfCells;i++)
1308 lgthOfCurCell=index[i+1]-posOfCurCell;
1309 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1310 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1311 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1315 switch(cm.getDimension())
1319 INTERP_KERNEL::AutoPtr<int> tmp=new int[lgthOfCurCell-1];
1320 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(int *)tmp);
1321 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1326 int nbOfFaces,lgthOfPolyhConn;
1327 INTERP_KERNEL::AutoPtr<int> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1328 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1333 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1337 ret=ret || (newType!=type);
1338 conn[newPos]=newType;
1340 posOfCurCell=index[i+1];
1345 std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1346 newPos+=lgthOfCurCell;
1347 posOfCurCell+=lgthOfCurCell;
1351 if(newPos!=initMeshLgth)
1352 _nodal_connec->reAlloc(newPos);
1359 * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1360 * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1361 * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells.
1363 * \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
1366 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1368 checkFullyDefined();
1369 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1370 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1371 MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1372 coords->recenterForMaxPrecision(eps);
1374 int nbOfCells=getNumberOfCells();
1375 const int *conn=_nodal_connec->getConstPointer();
1376 const int *index=_nodal_connec_index->getConstPointer();
1377 MCAuto<DataArrayInt> connINew=DataArrayInt::New();
1378 connINew->alloc(nbOfCells+1,1);
1379 int *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1380 MCAuto<DataArrayInt> connNew=DataArrayInt::New(); connNew->alloc(0,1);
1382 for(int i=0;i<nbOfCells;i++,connINewPtr++)
1384 if(conn[index[i]]==(int)INTERP_KERNEL::NORM_POLYHED)
1386 SimplifyPolyhedronCell(eps,coords,conn+index[i],conn+index[i+1],connNew);
1390 connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1391 *connINewPtr=connNew->getNumberOfTuples();
1394 setConnectivity(connNew,connINew,false);
1398 * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1399 * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1400 * the format of the returned DataArrayInt instance.
1402 * \return a newly allocated DataArrayInt sorted ascendingly of fetched node ids.
1403 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1405 DataArrayInt *MEDCouplingUMesh::computeFetchedNodeIds() const
1407 checkConnectivityFullyDefined();
1408 int nbOfCells=getNumberOfCells();
1409 const int *connIndex=_nodal_connec_index->getConstPointer();
1410 const int *conn=_nodal_connec->getConstPointer();
1411 const int *maxEltPt=std::max_element(_nodal_connec->begin(),_nodal_connec->end());
1412 int maxElt=maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1;
1413 std::vector<bool> retS(maxElt,false);
1414 for(int i=0;i<nbOfCells;i++)
1415 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1419 for(int i=0;i<maxElt;i++)
1422 DataArrayInt *ret=DataArrayInt::New();
1424 int *retPtr=ret->getPointer();
1425 for(int i=0;i<maxElt;i++)
1432 * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1433 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1435 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1437 int nbOfNodes((int)nodeIdsInUse.size()),nbOfCells(getNumberOfCells());
1438 const int *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1439 for(int i=0;i<nbOfCells;i++)
1440 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1443 if(conn[j]<nbOfNodes)
1444 nodeIdsInUse[conn[j]]=true;
1447 std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1448 throw INTERP_KERNEL::Exception(oss.str().c_str());
1454 * Finds nodes not used in any cell and returns an array giving a new id to every node
1455 * by excluding the unused nodes, for which the array holds -1. The result array is
1456 * a mapping in "Old to New" mode.
1457 * \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1458 * \return DataArrayInt * - a new instance of DataArrayInt. Its length is \a
1459 * this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1460 * if the node is unused or a new id else. The caller is to delete this
1461 * array using decrRef() as it is no more needed.
1462 * \throw If the coordinates array is not set.
1463 * \throw If the nodal connectivity of cells is not defined.
1464 * \throw If the nodal connectivity includes an invalid id.
1466 * \if ENABLE_EXAMPLES
1467 * \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1468 * \ref py_mcumesh_getNodeIdsInUse "Here is a Python example".
1470 * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1472 DataArrayInt *MEDCouplingUMesh::getNodeIdsInUse(int& nbrOfNodesInUse) const
1475 int nbOfNodes(getNumberOfNodes());
1476 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1477 ret->alloc(nbOfNodes,1);
1478 int *traducer=ret->getPointer();
1479 std::fill(traducer,traducer+nbOfNodes,-1);
1480 int nbOfCells=getNumberOfCells();
1481 const int *connIndex=_nodal_connec_index->getConstPointer();
1482 const int *conn=_nodal_connec->getConstPointer();
1483 for(int i=0;i<nbOfCells;i++)
1484 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1487 if(conn[j]<nbOfNodes)
1488 traducer[conn[j]]=1;
1491 std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1492 throw INTERP_KERNEL::Exception(oss.str().c_str());
1495 nbrOfNodesInUse=(int)std::count(traducer,traducer+nbOfNodes,1);
1496 std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1501 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1502 * For each cell in \b this the number of nodes constituting cell is computed.
1503 * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1504 * So for pohyhedrons some nodes can be counted several times in the returned result.
1506 * \return a newly allocated array
1507 * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1509 DataArrayInt *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1511 checkConnectivityFullyDefined();
1512 int nbOfCells=getNumberOfCells();
1513 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1514 ret->alloc(nbOfCells,1);
1515 int *retPtr=ret->getPointer();
1516 const int *conn=getNodalConnectivity()->getConstPointer();
1517 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1518 for(int i=0;i<nbOfCells;i++,retPtr++)
1520 if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1521 *retPtr=connI[i+1]-connI[i]-1;
1523 *retPtr=connI[i+1]-connI[i]-1-std::count(conn+connI[i]+1,conn+connI[i+1],-1);
1529 * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1530 * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1532 * \return DataArrayInt * - new object to be deallocated by the caller.
1533 * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1535 DataArrayInt *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1537 checkConnectivityFullyDefined();
1538 int nbOfCells=getNumberOfCells();
1539 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1540 ret->alloc(nbOfCells,1);
1541 int *retPtr=ret->getPointer();
1542 const int *conn=getNodalConnectivity()->getConstPointer();
1543 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1544 for(int i=0;i<nbOfCells;i++,retPtr++)
1546 std::set<int> s(conn+connI[i]+1,conn+connI[i+1]);
1547 if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1548 *retPtr=(int)s.size();
1552 *retPtr=(int)s.size();
1559 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1560 * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1562 * \return a newly allocated array
1564 DataArrayInt *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1566 checkConnectivityFullyDefined();
1567 int nbOfCells=getNumberOfCells();
1568 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1569 ret->alloc(nbOfCells,1);
1570 int *retPtr=ret->getPointer();
1571 const int *conn=getNodalConnectivity()->getConstPointer();
1572 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1573 for(int i=0;i<nbOfCells;i++,retPtr++,connI++)
1575 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1576 *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1582 * Removes unused nodes (the node coordinates array is shorten) and returns an array
1583 * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1584 * array mean that the corresponding old node is no more used.
1585 * \return DataArrayInt * - a new instance of DataArrayInt of length \a
1586 * this->getNumberOfNodes() before call of this method. The caller is to
1587 * delete this array using decrRef() as it is no more needed.
1588 * \throw If the coordinates array is not set.
1589 * \throw If the nodal connectivity of cells is not defined.
1590 * \throw If the nodal connectivity includes an invalid id.
1591 * \sa areAllNodesFetched
1593 * \if ENABLE_EXAMPLES
1594 * \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1595 * \ref py_mcumesh_zipCoordsTraducer "Here is a Python example".
1598 DataArrayInt *MEDCouplingUMesh::zipCoordsTraducer()
1600 return MEDCouplingPointSet::zipCoordsTraducer();
1604 * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1605 * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1607 int MEDCouplingUMesh::AreCellsEqual(const int *conn, const int *connI, int cell1, int cell2, int compType)
1612 return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1614 return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1616 return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1618 return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1620 return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1622 throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1626 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1628 int MEDCouplingUMesh::AreCellsEqualPolicy0(const int *conn, const int *connI, int cell1, int cell2)
1630 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1631 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1636 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1638 int MEDCouplingUMesh::AreCellsEqualPolicy1(const int *conn, const int *connI, int cell1, int cell2)
1640 int 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();
1652 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1653 int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1654 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1655 work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1656 return work!=tmp+sz1?1:0;
1659 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1662 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1669 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1671 int MEDCouplingUMesh::AreCellsEqualPolicy2(const int *conn, const int *connI, int cell1, int cell2)
1673 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1675 if(conn[connI[cell1]]==conn[connI[cell2]])
1677 std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1678 std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1686 * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1688 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const int *conn, const int *connI, int cell1, int cell2)
1690 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1692 std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1693 std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1700 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1702 int MEDCouplingUMesh::AreCellsEqualPolicy7(const int *conn, const int *connI, int cell1, int cell2)
1704 int sz=connI[cell1+1]-connI[cell1];
1705 if(sz==connI[cell2+1]-connI[cell2])
1707 if(conn[connI[cell1]]==conn[connI[cell2]])
1709 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1710 unsigned dim=cm.getDimension();
1716 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1717 int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1718 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1719 work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1724 std::reverse_iterator<int *> it1((int *)tmp+sz1);
1725 std::reverse_iterator<int *> it2((int *)tmp);
1726 if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1732 return work!=tmp+sz1?1:0;
1735 {//case of SEG2 and SEG3
1736 if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1738 if(!cm.isQuadratic())
1740 std::reverse_iterator<const int *> it1(conn+connI[cell1+1]);
1741 std::reverse_iterator<const int *> it2(conn+connI[cell1]+1);
1742 if(std::equal(it1,it2,conn+connI[cell2]+1))
1748 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])
1755 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1762 * This method find in candidate pool defined by 'candidates' the cells equal following the polycy 'compType'.
1763 * If any true is returned and the results will be put at the end of 'result' output parameter. If not false is returned
1764 * and result remains unchanged.
1765 * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1766 * If in 'candidates' pool -1 value is considered as an empty value.
1767 * WARNING this method returns only ONE set of result !
1769 bool MEDCouplingUMesh::AreCellsEqualInPool(const std::vector<int>& candidates, int compType, const int *conn, const int *connI, DataArrayInt *result)
1771 if(candidates.size()<1)
1774 std::vector<int>::const_iterator iter=candidates.begin();
1775 int start=(*iter++);
1776 for(;iter!=candidates.end();iter++)
1778 int status=AreCellsEqual(conn,connI,start,*iter,compType);
1783 result->pushBackSilent(start);
1787 result->pushBackSilent(*iter);
1789 result->pushBackSilent(status==2?(*iter+1):-(*iter+1));
1796 * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified
1798 * This method keeps the coordiantes of \a this. This method is time consuming.
1800 * \param [in] compType input specifying the technique used to compare cells each other.
1801 * - 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.
1802 * - 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)
1803 * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1804 * - 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
1805 * can be used for users not sensitive to orientation of cell
1806 * \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.
1807 * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1808 * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1809 * \return the correspondance array old to new in a newly allocated array.
1812 void MEDCouplingUMesh::findCommonCells(int compType, int startCellId, DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr) const
1814 MCAuto<DataArrayInt> revNodal=DataArrayInt::New(),revNodalI=DataArrayInt::New();
1815 getReverseNodalConnectivity(revNodal,revNodalI);
1816 FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1819 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, int startCellId, const DataArrayInt *nodal, const DataArrayInt *nodalI, const DataArrayInt *revNodal, const DataArrayInt *revNodalI,
1820 DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr)
1822 MCAuto<DataArrayInt> commonCells=DataArrayInt::New(),commonCellsI=DataArrayInt::New(); commonCells->alloc(0,1);
1823 int nbOfCells=nodalI->getNumberOfTuples()-1;
1824 commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1825 const int *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1826 const int *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1827 std::vector<bool> isFetched(nbOfCells,false);
1830 for(int i=0;i<nbOfCells;i++)
1834 const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1835 std::vector<int> v,v2;
1836 if(connOfNode!=connPtr+connIPtr[i+1])
1838 const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1839 v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1842 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1846 const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1847 std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1848 v2.resize(std::distance(v2.begin(),it));
1852 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1854 int pos=commonCellsI->back();
1855 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1856 for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1857 isFetched[*it]=true;
1865 for(int i=startCellId;i<nbOfCells;i++)
1869 const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1870 std::vector<int> v,v2;
1871 if(connOfNode!=connPtr+connIPtr[i+1])
1873 v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1876 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1880 std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1881 v2.resize(std::distance(v2.begin(),it));
1885 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1887 int pos=commonCellsI->back();
1888 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1889 for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1890 isFetched[*it]=true;
1896 commonCellsArr=commonCells.retn();
1897 commonCellsIArr=commonCellsI.retn();
1901 * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1902 * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1903 * than \a this->getNumberOfCells() in the returned array means that there is no
1904 * corresponding cell in \a this mesh.
1905 * It is expected that \a this and \a other meshes share the same node coordinates
1906 * array, if it is not so an exception is thrown.
1907 * \param [in] other - the mesh to compare with.
1908 * \param [in] compType - specifies a cell comparison technique. For meaning of its
1909 * valid values [0,1,2], see zipConnectivityTraducer().
1910 * \param [out] arr - a new instance of DataArrayInt returning correspondence
1911 * between cells of the two meshes. It contains \a other->getNumberOfCells()
1912 * values. The caller is to delete this array using
1913 * decrRef() as it is no more needed.
1914 * \return bool - \c true if all cells of \a other mesh are present in the \a this
1917 * \if ENABLE_EXAMPLES
1918 * \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1919 * \ref py_mcumesh_areCellsIncludedIn "Here is a Python example".
1921 * \sa checkDeepEquivalOnSameNodesWith()
1922 * \sa checkGeoEquivalWith()
1924 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayInt *& arr) const
1926 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1927 int nbOfCells=getNumberOfCells();
1928 static const int possibleCompType[]={0,1,2};
1929 if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1931 std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1932 std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1934 throw INTERP_KERNEL::Exception(oss.str().c_str());
1936 MCAuto<DataArrayInt> o2n=mesh->zipConnectivityTraducer(compType,nbOfCells);
1937 arr=o2n->subArray(nbOfCells);
1938 arr->setName(other->getName());
1940 if(other->getNumberOfCells()==0)
1942 return arr->getMaxValue(tmp)<nbOfCells;
1946 * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1947 * This method tries to determine if \b other is fully included in \b this.
1948 * The main difference is that this method is not expected to throw exception.
1949 * This method has two outputs :
1951 * \param other other mesh
1952 * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1953 * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
1955 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayInt *& arr) const
1957 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1958 DataArrayInt *commonCells=0,*commonCellsI=0;
1959 int thisNbCells=getNumberOfCells();
1960 mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
1961 MCAuto<DataArrayInt> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1962 const int *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
1963 int otherNbCells=other->getNumberOfCells();
1964 MCAuto<DataArrayInt> arr2=DataArrayInt::New();
1965 arr2->alloc(otherNbCells,1);
1966 arr2->fillWithZero();
1967 int *arr2Ptr=arr2->getPointer();
1968 int nbOfCommon=commonCellsI->getNumberOfTuples()-1;
1969 for(int i=0;i<nbOfCommon;i++)
1971 int start=commonCellsPtr[commonCellsIPtr[i]];
1972 if(start<thisNbCells)
1974 for(int j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
1976 int sig=commonCellsPtr[j]>0?1:-1;
1977 int val=std::abs(commonCellsPtr[j])-1;
1978 if(val>=thisNbCells)
1979 arr2Ptr[val-thisNbCells]=sig*(start+1);
1983 arr2->setName(other->getName());
1984 if(arr2->presenceOfValue(0))
1990 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
1993 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
1994 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
1996 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
1997 std::vector<const MEDCouplingUMesh *> ms(2);
2000 return MergeUMeshesOnSameCoords(ms);
2004 * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
2005 * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
2006 * cellIds is not given explicitely but by a range python like.
2011 * \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.
2012 * \return a newly allocated
2014 * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
2015 * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
2017 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(int start, int end, int step, bool keepCoords) const
2019 if(getMeshDimension()!=-1)
2020 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
2023 int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
2025 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2027 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2029 return const_cast<MEDCouplingUMesh *>(this);
2034 * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
2035 * The result mesh shares or not the node coordinates array with \a this mesh depending
2036 * on \a keepCoords parameter.
2037 * \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
2038 * to write this mesh to the MED file, its cells must be sorted using
2039 * sortCellsInMEDFileFrmt().
2040 * \param [in] begin - an array of cell ids to include to the new mesh.
2041 * \param [in] end - a pointer to last-plus-one-th element of \a begin.
2042 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2043 * array of \a this mesh, else "free" nodes are removed from the result mesh
2044 * by calling zipCoords().
2045 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2046 * to delete this mesh using decrRef() as it is no more needed.
2047 * \throw If the coordinates array is not set.
2048 * \throw If the nodal connectivity of cells is not defined.
2049 * \throw If any cell id in the array \a begin is not valid.
2051 * \if ENABLE_EXAMPLES
2052 * \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
2053 * \ref py_mcumesh_buildPartOfMySelf "Here is a Python example".
2056 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const int *begin, const int *end, bool keepCoords) const
2058 if(getMeshDimension()!=-1)
2059 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
2063 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2065 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2067 return const_cast<MEDCouplingUMesh *>(this);
2072 * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
2074 * 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.
2075 * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
2076 * The number of cells of \b this will remain the same with this method.
2078 * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
2079 * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
2080 * \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 ).
2081 * Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
2083 void MEDCouplingUMesh::setPartOfMySelf(const int *cellIdsBg, const int *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2085 checkConnectivityFullyDefined();
2086 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2087 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2088 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2089 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2091 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2092 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2093 throw INTERP_KERNEL::Exception(oss.str().c_str());
2095 int nbOfCellsToModify=(int)std::distance(cellIdsBg,cellIdsEnd);
2096 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2098 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2099 throw INTERP_KERNEL::Exception(oss.str().c_str());
2101 int nbOfCells=getNumberOfCells();
2102 bool easyAssign=true;
2103 const int *connI=_nodal_connec_index->getConstPointer();
2104 const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2105 for(const int *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2107 if(*it>=0 && *it<nbOfCells)
2109 easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2113 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2114 throw INTERP_KERNEL::Exception(oss.str().c_str());
2119 MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2124 DataArrayInt *arrOut=0,*arrIOut=0;
2125 MEDCouplingUMesh::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2127 MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2128 setConnectivity(arrOut,arrIOut,true);
2132 void MEDCouplingUMesh::setPartOfMySelfSlice(int start, int end, int step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2134 checkConnectivityFullyDefined();
2135 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2136 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2137 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2138 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2140 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2141 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2142 throw INTERP_KERNEL::Exception(oss.str().c_str());
2144 int nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2145 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2147 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2148 throw INTERP_KERNEL::Exception(oss.str().c_str());
2150 int nbOfCells=getNumberOfCells();
2151 bool easyAssign=true;
2152 const int *connI=_nodal_connec_index->getConstPointer();
2153 const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2155 for(int i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2157 if(it>=0 && it<nbOfCells)
2159 easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2163 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2164 throw INTERP_KERNEL::Exception(oss.str().c_str());
2169 MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2174 DataArrayInt *arrOut=0,*arrIOut=0;
2175 MEDCouplingUMesh::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2177 MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2178 setConnectivity(arrOut,arrIOut,true);
2183 * Keeps from \a this only cells which constituing point id are in the ids specified by [ \a begin,\a end ).
2184 * The resulting cell ids are stored at the end of the 'cellIdsKept' parameter.
2185 * Parameter \a fullyIn specifies if a cell that has part of its nodes in ids array is kept or not.
2186 * If \a fullyIn is true only cells whose ids are \b fully contained in [ \a begin,\a end ) tab will be kept.
2188 * \param [in] begin input start of array of node ids.
2189 * \param [in] end input end of array of node ids.
2190 * \param [in] fullyIn input that specifies if all node ids must be in [ \a begin,\a end ) array to consider cell to be in.
2191 * \param [in,out] cellIdsKeptArr array where all candidate cell ids are put at the end.
2193 void MEDCouplingUMesh::fillCellIdsToKeepFromNodeIds(const int *begin, const int *end, bool fullyIn, DataArrayInt *&cellIdsKeptArr) const
2195 MCAuto<DataArrayInt> cellIdsKept=DataArrayInt::New(); cellIdsKept->alloc(0,1);
2196 checkConnectivityFullyDefined();
2198 int sz=getNodalConnectivity()->getMaxValue(tmp); sz=std::max(sz,0)+1;
2199 std::vector<bool> fastFinder(sz,false);
2200 for(const int *work=begin;work!=end;work++)
2201 if(*work>=0 && *work<sz)
2202 fastFinder[*work]=true;
2203 int nbOfCells=getNumberOfCells();
2204 const int *conn=getNodalConnectivity()->getConstPointer();
2205 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2206 for(int i=0;i<nbOfCells;i++)
2208 int ref=0,nbOfHit=0;
2209 for(const int *work2=conn+connIndex[i]+1;work2!=conn+connIndex[i+1];work2++)
2213 if(fastFinder[*work2])
2216 if((ref==nbOfHit && fullyIn) || (nbOfHit!=0 && !fullyIn))
2217 cellIdsKept->pushBackSilent(i);
2219 cellIdsKeptArr=cellIdsKept.retn();
2223 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2224 * this->getMeshDimension(), that bound some cells of \a this mesh.
2225 * The cells of lower dimension to include to the result mesh are selected basing on
2226 * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2227 * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2228 * ==\c false, a cell is copied if any its node is in the array of node ids. The
2229 * created mesh shares the node coordinates array with \a this mesh.
2230 * \param [in] begin - the array of node ids.
2231 * \param [in] end - a pointer to the (last+1)-th element of \a begin.
2232 * \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2233 * array \a begin are added, else cells whose any node is in the
2234 * array \a begin are added.
2235 * \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2236 * to delete this mesh using decrRef() as it is no more needed.
2237 * \throw If the coordinates array is not set.
2238 * \throw If the nodal connectivity of cells is not defined.
2239 * \throw If any node id in \a begin is not valid.
2241 * \if ENABLE_EXAMPLES
2242 * \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2243 * \ref py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2246 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const int *begin, const int *end, bool fullyIn) const
2248 MCAuto<DataArrayInt> desc,descIndx,revDesc,revDescIndx;
2249 desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=DataArrayInt::New(); revDescIndx=DataArrayInt::New();
2250 MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2251 desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2252 return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2256 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2257 * this->getMeshDimension(), which bound only one cell of \a this mesh.
2258 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2259 * array of \a this mesh, else "free" nodes are removed from the result mesh
2260 * by calling zipCoords().
2261 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2262 * to delete this mesh using decrRef() as it is no more needed.
2263 * \throw If the coordinates array is not set.
2264 * \throw If the nodal connectivity of cells is not defined.
2266 * \if ENABLE_EXAMPLES
2267 * \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2268 * \ref py_mcumesh_buildBoundaryMesh "Here is a Python example".
2271 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2273 DataArrayInt *desc=DataArrayInt::New();
2274 DataArrayInt *descIndx=DataArrayInt::New();
2275 DataArrayInt *revDesc=DataArrayInt::New();
2276 DataArrayInt *revDescIndx=DataArrayInt::New();
2278 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2281 descIndx->decrRef();
2282 int nbOfCells=meshDM1->getNumberOfCells();
2283 const int *revDescIndxC=revDescIndx->getConstPointer();
2284 std::vector<int> boundaryCells;
2285 for(int i=0;i<nbOfCells;i++)
2286 if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2287 boundaryCells.push_back(i);
2288 revDescIndx->decrRef();
2289 MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2294 * This method returns a newly created DataArrayInt instance containing ids of cells located in boundary.
2295 * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2296 * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2298 DataArrayInt *MEDCouplingUMesh::findCellIdsOnBoundary() const
2300 checkFullyDefined();
2301 MCAuto<DataArrayInt> desc=DataArrayInt::New();
2302 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2303 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2304 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2306 buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2307 desc=(DataArrayInt*)0; descIndx=(DataArrayInt*)0;
2309 MCAuto<DataArrayInt> tmp=revDescIndx->deltaShiftIndex();
2310 MCAuto<DataArrayInt> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayInt*)0;
2311 const int *revDescPtr=revDesc->getConstPointer();
2312 const int *revDescIndxPtr=revDescIndx->getConstPointer();
2313 int nbOfCells=getNumberOfCells();
2314 std::vector<bool> ret1(nbOfCells,false);
2316 for(const int *pt=faceIds->begin();pt!=faceIds->end();pt++)
2317 if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2318 { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2320 DataArrayInt *ret2=DataArrayInt::New();
2322 int *ret2Ptr=ret2->getPointer();
2324 for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2327 ret2->setName("BoundaryCells");
2332 * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2333 * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2334 * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2335 * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2337 * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2338 * 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
2339 * equals a cell in \b otherDimM1OnSameCoords.
2341 * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2342 * are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2344 * \param [in] otherDimM1OnSameCoords
2345 * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2346 * \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
2347 * cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2349 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *&cellIdsRk0, DataArrayInt *&cellIdsRk1) const
2351 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2352 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2353 checkConnectivityFullyDefined();
2354 otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2355 if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2356 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2357 MCAuto<DataArrayInt> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2358 MCAuto<DataArrayInt> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2359 MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2360 MCAuto<DataArrayInt> descThisPart=DataArrayInt::New(),descIThisPart=DataArrayInt::New(),revDescThisPart=DataArrayInt::New(),revDescIThisPart=DataArrayInt::New();
2361 MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2362 const int *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2363 DataArrayInt *idsOtherInConsti=0;
2364 bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2365 MCAuto<DataArrayInt> idsOtherInConstiAuto(idsOtherInConsti);
2367 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2369 for(const int *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2370 s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2371 MCAuto<DataArrayInt> s1arr_renum1=DataArrayInt::New(); s1arr_renum1->alloc((int)s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2372 s1arr_renum1->sort();
2373 cellIdsRk0=s0arr.retn();
2374 //cellIdsRk1=s_renum1.retn();
2375 cellIdsRk1=s1arr_renum1.retn();
2379 * 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
2380 * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2382 * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2384 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2386 MCAuto<DataArrayInt> desc=DataArrayInt::New();
2387 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2388 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2389 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2391 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2392 revDesc=0; desc=0; descIndx=0;
2393 MCAuto<DataArrayInt> revDescIndx2=revDescIndx->deltaShiftIndex();
2394 MCAuto<DataArrayInt> part=revDescIndx2->findIdsEqual(1);
2395 return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2399 * Finds nodes lying on the boundary of \a this mesh.
2400 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of found
2401 * nodes. The caller is to delete this array using decrRef() as it is no
2403 * \throw If the coordinates array is not set.
2404 * \throw If the nodal connectivity of cells is node defined.
2406 * \if ENABLE_EXAMPLES
2407 * \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2408 * \ref py_mcumesh_findBoundaryNodes "Here is a Python example".
2411 DataArrayInt *MEDCouplingUMesh::findBoundaryNodes() const
2413 MCAuto<MEDCouplingUMesh> skin=computeSkin();
2414 return skin->computeFetchedNodeIds();
2417 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2420 return const_cast<MEDCouplingUMesh *>(this);
2424 * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2425 * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2426 * 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.
2427 * If a node is in the boundary of \b this \b and in the boundary of \b otherDimM1OnSameCoords this node is considerd as needed to be duplicated.
2428 * 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.
2430 * \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
2431 * parameter is altered during the call.
2432 * \param [out] nodeIdsToDuplicate node ids needed to be duplicated following the algorithm explain above.
2433 * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2434 * \param [out] cellIdsNotModified cell ids int \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.
2436 * \warning This method modifies param \b otherDimM1OnSameCoords (for speed reasons).
2438 void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *& nodeIdsToDuplicate,
2439 DataArrayInt *& cellIdsNeededToBeRenum, DataArrayInt *& cellIdsNotModified) const
2441 typedef MCAuto<DataArrayInt> DAInt;
2443 checkFullyDefined();
2444 otherDimM1OnSameCoords.checkFullyDefined();
2445 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2446 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2447 if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2448 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2449 DataArrayInt *cellIdsRk0=0,*cellIdsRk1=0;
2450 findCellIdsLyingOn(otherDimM1OnSameCoords,cellIdsRk0,cellIdsRk1);
2451 DAInt cellIdsRk0Auto(cellIdsRk0),cellIdsRk1Auto(cellIdsRk1);
2452 DAInt s0=cellIdsRk1->buildComplement(cellIdsRk0->getNumberOfTuples());
2453 s0->transformWithIndArr(cellIdsRk0Auto->begin(),cellIdsRk0Auto->end());
2454 MCAuto<MEDCouplingUMesh> m0Part=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0->begin(),s0->end(),true));
2455 DAInt s1=m0Part->computeFetchedNodeIds();
2456 DAInt s2=otherDimM1OnSameCoords.computeFetchedNodeIds();
2457 DAInt s3=s2->buildSubstraction(s1);
2458 cellIdsRk1->transformWithIndArr(cellIdsRk0Auto->begin(),cellIdsRk0Auto->end());
2460 MCAuto<MEDCouplingUMesh> m0Part2=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellIdsRk1->begin(),cellIdsRk1->end(),true));
2461 int nCells2 = m0Part2->getNumberOfCells();
2462 DAInt desc00=DataArrayInt::New(),descI00=DataArrayInt::New(),revDesc00=DataArrayInt::New(),revDescI00=DataArrayInt::New();
2463 MCAuto<MEDCouplingUMesh> m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00);
2464 // Neighbor information of the mesh without considering the crack (serves to count how many connex pieces it is made of)
2465 DataArrayInt *tmp00=0,*tmp11=0;
2466 MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00, tmp00, tmp11);
2467 DAInt neighInit00(tmp00);
2468 DAInt neighIInit00(tmp11);
2469 // Neighbor information of the mesh WITH the crack (some neighbors are removed):
2470 DataArrayInt *idsTmp=0;
2471 bool b=m01->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsTmp);
2474 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the given mdim-1 mesh in other is not a constituent of this !");
2475 // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2476 // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2477 MEDCouplingUMesh::RemoveIdsFromIndexedArrays(ids->begin(),ids->end(),desc00,descI00);
2478 DataArrayInt *tmp0=0,*tmp1=0;
2479 // Compute the neighbor of each cell in m0Part2, taking into account the broken link above. Two
2480 // cells on either side of the crack (defined by the mesh of low dimension) are not neighbor anymore.
2481 ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00,tmp0,tmp1);
2482 DAInt neigh00(tmp0);
2483 DAInt neighI00(tmp1);
2485 // For each initial connex part of the sub-mesh (or said differently for each independent crack):
2486 int seed = 0, nIter = 0;
2487 int nIterMax = nCells2+1; // Safety net for the loop
2488 DAInt hitCells = DataArrayInt::New(); hitCells->alloc(nCells2);
2489 hitCells->fillWithValue(-1);
2490 DAInt cellsToModifyConn0_torenum = DataArrayInt::New();
2491 cellsToModifyConn0_torenum->alloc(0,1);
2492 while (nIter < nIterMax)
2494 DAInt t = hitCells->findIdsEqual(-1);
2495 if (!t->getNumberOfTuples())
2497 // Connex zone without the crack (to compute the next seed really)
2499 DAInt connexCheck = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neighInit00,neighIInit00, -1, dnu);
2501 for (int * ptr = connexCheck->getPointer(); cnt < connexCheck->getNumberOfTuples(); ptr++, cnt++)
2502 hitCells->setIJ(*ptr,0,1);
2503 // Connex zone WITH the crack (to identify cells lying on either part of the crack)
2504 DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neigh00,neighI00, -1, dnu);
2505 cellsToModifyConn0_torenum = DataArrayInt::Aggregate(cellsToModifyConn0_torenum, spreadZone, 0);
2506 // Compute next seed, i.e. a cell in another connex part, which was not covered by the previous iterations
2507 DAInt comple = cellsToModifyConn0_torenum->buildComplement(nCells2);
2508 DAInt nonHitCells = hitCells->findIdsEqual(-1);
2509 DAInt intersec = nonHitCells->buildIntersection(comple);
2510 if (intersec->getNumberOfTuples())
2511 { seed = intersec->getIJ(0,0); }
2516 if (nIter >= nIterMax)
2517 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate(): internal error - too many iterations.");
2519 DAInt cellsToModifyConn1_torenum=cellsToModifyConn0_torenum->buildComplement(neighI00->getNumberOfTuples()-1);
2520 cellsToModifyConn0_torenum->transformWithIndArr(cellIdsRk1->begin(),cellIdsRk1->end());
2521 cellsToModifyConn1_torenum->transformWithIndArr(cellIdsRk1->begin(),cellIdsRk1->end());
2523 cellIdsNeededToBeRenum=cellsToModifyConn0_torenum.retn();
2524 cellIdsNotModified=cellsToModifyConn1_torenum.retn();
2525 nodeIdsToDuplicate=s3.retn();
2529 * This method operates a modification of the connectivity and coords in \b this.
2530 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2531 * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2532 * More explicitely the renumber array in nodes is not explicitely given in old2new to avoid to build a big array of renumbering whereas typically few node ids needs to be
2533 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2534 * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2536 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2538 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2539 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2541 void MEDCouplingUMesh::duplicateNodes(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd)
2543 int nbOfNodes=getNumberOfNodes();
2544 duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2545 duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2549 * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2550 * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2552 * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2554 * \sa renumberNodesInConn
2556 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(int offset)
2558 checkConnectivityFullyDefined();
2559 int *conn(getNodalConnectivity()->getPointer());
2560 const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2561 int nbOfCells(getNumberOfCells());
2562 for(int i=0;i<nbOfCells;i++)
2563 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2565 int& node=conn[iconn];
2566 if(node>=0)//avoid polyhedron separator
2571 _nodal_connec->declareAsNew();
2576 * Same than renumberNodesInConn(const int *) except that here the format of old-to-new traducer is using map instead
2577 * 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
2580 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<int,int>& newNodeNumbersO2N)
2582 checkConnectivityFullyDefined();
2583 int *conn(getNodalConnectivity()->getPointer());
2584 const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2585 int nbOfCells(getNumberOfCells());
2586 for(int i=0;i<nbOfCells;i++)
2587 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2589 int& node=conn[iconn];
2590 if(node>=0)//avoid polyhedron separator
2592 INTERP_KERNEL::HashMap<int,int>::const_iterator it(newNodeNumbersO2N.find(node));
2593 if(it!=newNodeNumbersO2N.end())
2599 std::ostringstream oss; oss << "MEDCouplingUMesh::renumberNodesInConn(map) : presence in connectivity for cell #" << i << " of node #" << node << " : Not in map !";
2600 throw INTERP_KERNEL::Exception(oss.str().c_str());
2604 _nodal_connec->declareAsNew();
2609 * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2610 * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2611 * This method is a generalization of shiftNodeNumbersInConn().
2612 * \warning This method performs no check of validity of new ids. **Use it with care !**
2613 * \param [in] newNodeNumbersO2N - a permutation array, of length \a
2614 * this->getNumberOfNodes(), in "Old to New" mode.
2615 * See \ref numbering for more info on renumbering modes.
2616 * \throw If the nodal connectivity of cells is not defined.
2618 * \if ENABLE_EXAMPLES
2619 * \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2620 * \ref py_mcumesh_renumberNodesInConn "Here is a Python example".
2623 void MEDCouplingUMesh::renumberNodesInConn(const int *newNodeNumbersO2N)
2625 checkConnectivityFullyDefined();
2626 int *conn=getNodalConnectivity()->getPointer();
2627 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2628 int nbOfCells(getNumberOfCells());
2629 for(int i=0;i<nbOfCells;i++)
2630 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2632 int& node=conn[iconn];
2633 if(node>=0)//avoid polyhedron separator
2635 node=newNodeNumbersO2N[node];
2638 _nodal_connec->declareAsNew();
2643 * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2644 * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2645 * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2647 * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2649 void MEDCouplingUMesh::shiftNodeNumbersInConn(int delta)
2651 checkConnectivityFullyDefined();
2652 int *conn=getNodalConnectivity()->getPointer();
2653 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2654 int nbOfCells=getNumberOfCells();
2655 for(int i=0;i<nbOfCells;i++)
2656 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2658 int& node=conn[iconn];
2659 if(node>=0)//avoid polyhedron separator
2664 _nodal_connec->declareAsNew();
2669 * This method operates a modification of the connectivity in \b this.
2670 * 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.
2671 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2672 * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2673 * More explicitely the renumber array in nodes is not explicitely given in old2new to avoid to build a big array of renumbering whereas typically few node ids needs to be
2674 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2675 * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2677 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2678 * As an another consequense after the call of this method \b this can be transiently non cohrent.
2680 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2681 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2682 * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ).
2684 void MEDCouplingUMesh::duplicateNodesInConn(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd, int offset)
2686 checkConnectivityFullyDefined();
2687 std::map<int,int> m;
2689 for(const int *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2691 int *conn=getNodalConnectivity()->getPointer();
2692 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2693 int nbOfCells=getNumberOfCells();
2694 for(int i=0;i<nbOfCells;i++)
2695 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2697 int& node=conn[iconn];
2698 if(node>=0)//avoid polyhedron separator
2700 std::map<int,int>::iterator it=m.find(node);
2709 * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2711 * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2712 * After the call of this method the number of cells remains the same as before.
2714 * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2715 * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2716 * be strictly in [0;this->getNumberOfCells()).
2718 * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2719 * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2720 * should be contained in[0;this->getNumberOfCells()).
2722 * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2725 void MEDCouplingUMesh::renumberCells(const int *old2NewBg, bool check)
2727 checkConnectivityFullyDefined();
2728 int nbCells=getNumberOfCells();
2729 const int *array=old2NewBg;
2731 array=DataArrayInt::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2733 const int *conn=_nodal_connec->getConstPointer();
2734 const int *connI=_nodal_connec_index->getConstPointer();
2735 MCAuto<DataArrayInt> o2n=DataArrayInt::New(); o2n->useArray(array,false,C_DEALLOC,nbCells,1);
2736 MCAuto<DataArrayInt> n2o=o2n->invertArrayO2N2N2O(nbCells);
2737 const int *n2oPtr=n2o->begin();
2738 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
2739 newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2740 newConn->copyStringInfoFrom(*_nodal_connec);
2741 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
2742 newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2743 newConnI->copyStringInfoFrom(*_nodal_connec_index);
2745 int *newC=newConn->getPointer();
2746 int *newCI=newConnI->getPointer();
2749 for(int i=0;i<nbCells;i++)
2752 int nbOfElts=connI[pos+1]-connI[pos];
2753 newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2758 setConnectivity(newConn,newConnI);
2760 free(const_cast<int *>(array));
2764 * Finds cells whose bounding boxes intersect a given bounding box.
2765 * \param [in] bbox - an array defining the bounding box via coordinates of its
2766 * extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2768 * \param [in] eps - a factor used to increase size of the bounding box of cell
2769 * before comparing it with \a bbox. This factor is multiplied by the maximal
2770 * extent of the bounding box of cell to produce an addition to this bounding box.
2771 * \return DataArrayInt * - a new instance of DataArrayInt holding ids for found
2772 * cells. The caller is to delete this array using decrRef() as it is no more
2774 * \throw If the coordinates array is not set.
2775 * \throw If the nodal connectivity of cells is not defined.
2777 * \if ENABLE_EXAMPLES
2778 * \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2779 * \ref py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2782 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2784 MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2785 if(getMeshDimension()==-1)
2787 elems->pushBackSilent(0);
2788 return elems.retn();
2790 int dim=getSpaceDimension();
2791 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2792 const int* conn = getNodalConnectivity()->getConstPointer();
2793 const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2794 const double* coords = getCoords()->getConstPointer();
2795 int nbOfCells=getNumberOfCells();
2796 for ( int ielem=0; ielem<nbOfCells;ielem++ )
2798 for (int i=0; i<dim; i++)
2800 elem_bb[i*2]=std::numeric_limits<double>::max();
2801 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2804 for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2806 int node= conn[inode];
2807 if(node>=0)//avoid polyhedron separator
2809 for (int idim=0; idim<dim; idim++)
2811 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2813 elem_bb[idim*2] = coords[node*dim+idim] ;
2815 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2817 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2822 if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2823 elems->pushBackSilent(ielem);
2825 return elems.retn();
2829 * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2830 * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2831 * added in 'elems' parameter.
2833 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2835 MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2836 if(getMeshDimension()==-1)
2838 elems->pushBackSilent(0);
2839 return elems.retn();
2841 int dim=getSpaceDimension();
2842 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2843 const int* conn = getNodalConnectivity()->getConstPointer();
2844 const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2845 const double* coords = getCoords()->getConstPointer();
2846 int nbOfCells=getNumberOfCells();
2847 for ( int ielem=0; ielem<nbOfCells;ielem++ )
2849 for (int i=0; i<dim; i++)
2851 elem_bb[i*2]=std::numeric_limits<double>::max();
2852 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2855 for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2857 int node= conn[inode];
2858 if(node>=0)//avoid polyhedron separator
2860 for (int idim=0; idim<dim; idim++)
2862 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2864 elem_bb[idim*2] = coords[node*dim+idim] ;
2866 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2868 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2873 if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
2874 elems->pushBackSilent(ielem);
2876 return elems.retn();
2880 * Returns a type of a cell by its id.
2881 * \param [in] cellId - the id of the cell of interest.
2882 * \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
2883 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2885 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(int cellId) const
2887 const int *ptI=_nodal_connec_index->getConstPointer();
2888 const int *pt=_nodal_connec->getConstPointer();
2889 if(cellId>=0 && cellId<(int)_nodal_connec_index->getNbOfElems()-1)
2890 return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2893 std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2894 throw INTERP_KERNEL::Exception(oss.str().c_str());
2899 * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2900 * This method does not throw exception if geometric type \a type is not in \a this.
2901 * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2902 * The coordinates array is not considered here.
2904 * \param [in] type the geometric type
2905 * \return cell ids in this having geometric type \a type.
2907 DataArrayInt *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2910 MCAuto<DataArrayInt> ret=DataArrayInt::New();
2912 checkConnectivityFullyDefined();
2913 int nbCells=getNumberOfCells();
2914 int mdim=getMeshDimension();
2915 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
2916 if(mdim!=(int)cm.getDimension())
2917 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
2918 const int *ptI=_nodal_connec_index->getConstPointer();
2919 const int *pt=_nodal_connec->getConstPointer();
2920 for(int i=0;i<nbCells;i++)
2922 if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
2923 ret->pushBackSilent(i);
2929 * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
2931 int MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2933 const int *ptI=_nodal_connec_index->getConstPointer();
2934 const int *pt=_nodal_connec->getConstPointer();
2935 int nbOfCells=getNumberOfCells();
2937 for(int i=0;i<nbOfCells;i++)
2938 if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
2944 * Returns the nodal connectivity of a given cell.
2945 * The separator of faces within polyhedron connectivity (-1) is not returned, thus
2946 * all returned node ids can be used in getCoordinatesOfNode().
2947 * \param [in] cellId - an id of the cell of interest.
2948 * \param [in,out] conn - a vector where the node ids are appended. It is not
2949 * cleared before the appending.
2950 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2952 void MEDCouplingUMesh::getNodeIdsOfCell(int cellId, std::vector<int>& conn) const
2954 const int *ptI=_nodal_connec_index->getConstPointer();
2955 const int *pt=_nodal_connec->getConstPointer();
2956 for(const int *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
2961 std::string MEDCouplingUMesh::simpleRepr() const
2963 static const char msg0[]="No coordinates specified !";
2964 std::ostringstream ret;
2965 ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
2966 ret << "Description of mesh : \"" << getDescription() << "\"\n";
2968 double tt=getTime(tmpp1,tmpp2);
2969 ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
2970 ret << "Iteration : " << tmpp1 << " Order : " << tmpp2 << "\n";
2972 { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
2974 { ret << " Mesh dimension has not been set or is invalid !"; }
2977 const int spaceDim=getSpaceDimension();
2978 ret << spaceDim << "\nInfo attached on space dimension : ";
2979 for(int i=0;i<spaceDim;i++)
2980 ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
2984 ret << msg0 << "\n";
2985 ret << "Number of nodes : ";
2987 ret << getNumberOfNodes() << "\n";
2989 ret << msg0 << "\n";
2990 ret << "Number of cells : ";
2991 if(_nodal_connec!=0 && _nodal_connec_index!=0)
2992 ret << getNumberOfCells() << "\n";
2994 ret << "No connectivity specified !" << "\n";
2995 ret << "Cell types present : ";
2996 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
2998 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
2999 ret << cm.getRepr() << " ";
3005 std::string MEDCouplingUMesh::advancedRepr() const
3007 std::ostringstream ret;
3008 ret << simpleRepr();
3009 ret << "\nCoordinates array : \n___________________\n\n";
3011 _coords->reprWithoutNameStream(ret);
3013 ret << "No array set !\n";
3014 ret << "\n\nConnectivity arrays : \n_____________________\n\n";
3015 reprConnectivityOfThisLL(ret);
3020 * This method returns a C++ code that is a dump of \a this.
3021 * This method will throw if this is not fully defined.
3023 std::string MEDCouplingUMesh::cppRepr() const
3025 static const char coordsName[]="coords";
3026 static const char connName[]="conn";
3027 static const char connIName[]="connI";
3028 checkFullyDefined();
3029 std::ostringstream ret; ret << "// coordinates" << std::endl;
3030 _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
3031 _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
3032 _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
3033 ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
3034 ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
3035 ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
3036 ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
3040 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
3042 std::ostringstream ret;
3043 reprConnectivityOfThisLL(ret);
3048 * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsability to deal with.
3049 * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
3050 * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
3053 * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
3054 * 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
3055 * with number of tuples set to 0, if not the array is taken as this in the returned instance.
3057 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(int spaceDim) const
3059 int mdim=getMeshDimension();
3061 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
3062 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
3063 MCAuto<DataArrayInt> tmp1,tmp2;
3064 bool needToCpyCT=true;
3067 tmp1=DataArrayInt::New(); tmp1->alloc(0,1);
3075 if(!_nodal_connec_index)
3077 tmp2=DataArrayInt::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
3082 tmp2=_nodal_connec_index;
3085 ret->setConnectivity(tmp1,tmp2,false);
3090 MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
3091 ret->setCoords(coords);
3094 ret->setCoords(_coords);
3098 void MEDCouplingUMesh::reprConnectivityOfThisLL(std::ostringstream& stream) const
3100 if(_nodal_connec!=0 && _nodal_connec_index!=0)
3102 int nbOfCells=getNumberOfCells();
3103 const int *c=_nodal_connec->getConstPointer();
3104 const int *ci=_nodal_connec_index->getConstPointer();
3105 for(int i=0;i<nbOfCells;i++)
3107 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[i]]);
3108 stream << "Cell #" << i << " " << cm.getRepr() << " : ";
3109 std::copy(c+ci[i]+1,c+ci[i+1],std::ostream_iterator<int>(stream," "));
3114 stream << "Connectivity not defined !\n";
3117 int MEDCouplingUMesh::getNumberOfNodesInCell(int cellId) const
3119 const int *ptI=_nodal_connec_index->getConstPointer();
3120 const int *pt=_nodal_connec->getConstPointer();
3121 if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
3122 return ptI[cellId+1]-ptI[cellId]-1;
3124 return (int)std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind2nd(std::not_equal_to<int>(),-1));
3128 * Returns types of cells of the specified part of \a this mesh.
3129 * This method avoids computing sub-mesh explicitely to get its types.
3130 * \param [in] begin - an array of cell ids of interest.
3131 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3132 * \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3133 * describing the cell types.
3134 * \throw If the coordinates array is not set.
3135 * \throw If the nodal connectivity of cells is not defined.
3136 * \sa getAllGeoTypes()
3138 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const int *begin, const int *end) const
3140 checkFullyDefined();
3141 std::set<INTERP_KERNEL::NormalizedCellType> ret;
3142 const int *conn=_nodal_connec->getConstPointer();
3143 const int *connIndex=_nodal_connec_index->getConstPointer();
3144 for(const int *w=begin;w!=end;w++)
3145 ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3150 * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3151 * Optionally updates
3152 * a set of types of cells constituting \a this mesh.
3153 * This method is for advanced users having prepared their connectivity before. For
3154 * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3155 * \param [in] conn - the nodal connectivity array.
3156 * \param [in] connIndex - the nodal connectivity index array.
3157 * \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3160 void MEDCouplingUMesh::setConnectivity(DataArrayInt *conn, DataArrayInt *connIndex, bool isComputingTypes)
3162 DataArrayInt::SetArrayIn(conn,_nodal_connec);
3163 DataArrayInt::SetArrayIn(connIndex,_nodal_connec_index);
3164 if(isComputingTypes)
3170 * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3171 * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3173 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCopy):MEDCouplingPointSet(other,deepCopy),_mesh_dim(other._mesh_dim),
3174 _nodal_connec(0),_nodal_connec_index(0),
3175 _types(other._types)
3177 if(other._nodal_connec)
3178 _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCopy);
3179 if(other._nodal_connec_index)
3180 _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCopy);
3183 MEDCouplingUMesh::~MEDCouplingUMesh()
3186 _nodal_connec->decrRef();
3187 if(_nodal_connec_index)
3188 _nodal_connec_index->decrRef();
3192 * Recomputes a set of cell types of \a this mesh. For more info see
3193 * \ref MEDCouplingUMeshNodalConnectivity.
3195 void MEDCouplingUMesh::computeTypes()
3197 ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3201 * This method checks that all arrays are set. If yes nothing done if no an exception is thrown.
3203 void MEDCouplingUMesh::checkFullyDefined() const
3205 if(!_nodal_connec_index || !_nodal_connec || !_coords)
3206 throw INTERP_KERNEL::Exception("Reverse nodal connectivity computation requires full connectivity and coordinates set in unstructured mesh.");
3210 * This method checks that all connectivity arrays are set. If yes nothing done if no an exception is thrown.
3212 void MEDCouplingUMesh::checkConnectivityFullyDefined() const
3214 if(!_nodal_connec_index || !_nodal_connec)
3215 throw INTERP_KERNEL::Exception("Reverse nodal connectivity computation requires full connectivity set in unstructured mesh.");
3219 * Returns a number of cells constituting \a this mesh.
3220 * \return int - the number of cells in \a this mesh.
3221 * \throw If the nodal connectivity of cells is not defined.
3223 int MEDCouplingUMesh::getNumberOfCells() const
3225 if(_nodal_connec_index)
3226 return _nodal_connec_index->getNumberOfTuples()-1;
3231 throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3235 * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3236 * mesh. For more info see \ref meshes.
3237 * \return int - the dimension of \a this mesh.
3238 * \throw If the mesh dimension is not defined using setMeshDimension().
3240 int MEDCouplingUMesh::getMeshDimension() const
3243 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3248 * Returns a length of the nodal connectivity array.
3249 * This method is for test reason. Normally the integer returned is not useable by
3250 * user. For more info see \ref MEDCouplingUMeshNodalConnectivity.
3251 * \return int - the length of the nodal connectivity array.
3253 int MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3255 return _nodal_connec->getNbOfElems();
3259 * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3261 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<int>& tinyInfo, std::vector<std::string>& littleStrings) const
3263 MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3264 tinyInfo.push_back(getMeshDimension());
3265 tinyInfo.push_back(getNumberOfCells());
3267 tinyInfo.push_back(getNodalConnectivityArrayLen());
3269 tinyInfo.push_back(-1);
3273 * First step of unserialization process.
3275 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<int>& tinyInfo) const
3277 return tinyInfo[6]<=0;
3281 * Second step of serialization process.
3282 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3285 * \param littleStrings
3287 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<int>& tinyInfo, DataArrayInt *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3289 MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3291 a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3295 * Third and final step of serialization process.
3297 void MEDCouplingUMesh::serialize(DataArrayInt *&a1, DataArrayDouble *&a2) const
3299 MEDCouplingPointSet::serialize(a1,a2);
3300 if(getMeshDimension()>-1)
3302 a1=DataArrayInt::New();
3303 a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3304 int *ptA1=a1->getPointer();
3305 const int *conn=getNodalConnectivity()->getConstPointer();
3306 const int *index=getNodalConnectivityIndex()->getConstPointer();
3307 ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3308 std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3315 * Second and final unserialization process.
3316 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3318 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<int>& tinyInfo, const DataArrayInt *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3320 MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3321 setMeshDimension(tinyInfo[5]);
3325 const int *recvBuffer=a1->getConstPointer();
3326 MCAuto<DataArrayInt> myConnecIndex=DataArrayInt::New();
3327 myConnecIndex->alloc(tinyInfo[6]+1,1);
3328 std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3329 MCAuto<DataArrayInt> myConnec=DataArrayInt::New();
3330 myConnec->alloc(tinyInfo[7],1);
3331 std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3332 setConnectivity(myConnec, myConnecIndex);
3337 * This is the low algorithm of MEDCouplingUMesh::buildPartOfMySelfSlice.
3338 * CellIds are given using range specified by a start an end and step.
3340 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice(int start, int end, int step) const
3342 checkFullyDefined();
3343 int ncell=getNumberOfCells();
3344 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New();
3345 ret->_mesh_dim=_mesh_dim;
3346 ret->setCoords(_coords);
3347 int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice : ");
3348 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(newNbOfCells+1,1);
3349 int *newConnIPtr=newConnI->getPointer(); *newConnIPtr=0;
3351 const int *conn=_nodal_connec->getConstPointer();
3352 const int *connIndex=_nodal_connec_index->getConstPointer();
3353 for(int i=0;i<newNbOfCells;i++,newConnIPtr++,work+=step)
3355 if(work>=0 && work<ncell)
3357 newConnIPtr[1]=newConnIPtr[0]+connIndex[work+1]-connIndex[work];
3361 std::ostringstream oss; oss << "MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice : On pos #" << i << " input cell id =" << work << " should be in [0," << ncell << ") !";
3362 throw INTERP_KERNEL::Exception(oss.str().c_str());
3365 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(newConnIPtr[0],1);
3366 int *newConnPtr=newConn->getPointer();
3367 std::set<INTERP_KERNEL::NormalizedCellType> types;
3369 for(int i=0;i<newNbOfCells;i++,newConnIPtr++,work+=step)
3371 types.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[work]]);
3372 newConnPtr=std::copy(conn+connIndex[work],conn+connIndex[work+1],newConnPtr);
3374 ret->setConnectivity(newConn,newConnI,false);
3376 ret->copyTinyInfoFrom(this);
3381 * This is the low algorithm of MEDCouplingUMesh::buildPartOfMySelf.
3382 * Keeps from \a this only cells which constituing point id are in the ids specified by [ \a begin,\a end ).
3383 * The return newly allocated mesh will share the same coordinates as \a this.
3385 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfKeepCoords(const int *begin, const int *end) const
3387 checkConnectivityFullyDefined();
3388 int ncell=getNumberOfCells();
3389 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New();
3390 ret->_mesh_dim=_mesh_dim;
3391 ret->setCoords(_coords);
3392 std::size_t nbOfElemsRet=std::distance(begin,end);
3393 int *connIndexRet=(int *)malloc((nbOfElemsRet+1)*sizeof(int));
3395 const int *conn=_nodal_connec->getConstPointer();
3396 const int *connIndex=_nodal_connec_index->getConstPointer();
3398 for(const int *work=begin;work!=end;work++,newNbring++)
3400 if(*work>=0 && *work<ncell)
3401 connIndexRet[newNbring+1]=connIndexRet[newNbring]+connIndex[*work+1]-connIndex[*work];
3405 std::ostringstream oss; oss << "MEDCouplingUMesh::buildPartOfMySelfKeepCoords : On pos #" << std::distance(begin,work) << " input cell id =" << *work << " should be in [0," << ncell << ") !";
3406 throw INTERP_KERNEL::Exception(oss.str().c_str());
3409 int *connRet=(int *)malloc(connIndexRet[nbOfElemsRet]*sizeof(int));
3410 int *connRetWork=connRet;
3411 std::set<INTERP_KERNEL::NormalizedCellType> types;
3412 for(const int *work=begin;work!=end;work++)
3414 types.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*work]]);
3415 connRetWork=std::copy(conn+connIndex[*work],conn+connIndex[*work+1],connRetWork);
3417 MCAuto<DataArrayInt> connRetArr=DataArrayInt::New();
3418 connRetArr->useArray(connRet,true,C_DEALLOC,connIndexRet[nbOfElemsRet],1);
3419 MCAuto<DataArrayInt> connIndexRetArr=DataArrayInt::New();
3420 connIndexRetArr->useArray(connIndexRet,true,C_DEALLOC,(int)nbOfElemsRet+1,1);
3421 ret->setConnectivity(connRetArr,connIndexRetArr,false);
3423 ret->copyTinyInfoFrom(this);
3428 * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3430 * For 1D cells, the returned field contains lengths.<br>
3431 * For 2D cells, the returned field contains areas.<br>
3432 * For 3D cells, the returned field contains volumes.
3433 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3434 * orientation, i.e. the volume is always positive.
3435 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3436 * and one time . The caller is to delete this field using decrRef() as it is no
3439 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3441 std::string name="MeasureOfMesh_";
3443 int nbelem=getNumberOfCells();
3444 MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3445 field->setName(name);
3446 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3447 array->alloc(nbelem,1);
3448 double *area_vol=array->getPointer();
3449 field->setArray(array) ; array=0;
3450 field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3451 field->synchronizeTimeWithMesh();
3452 if(getMeshDimension()!=-1)
3455 INTERP_KERNEL::NormalizedCellType type;
3456 int dim_space=getSpaceDimension();
3457 const double *coords=getCoords()->getConstPointer();
3458 const int *connec=getNodalConnectivity()->getConstPointer();
3459 const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3460 for(int iel=0;iel<nbelem;iel++)
3462 ipt=connec_index[iel];
3463 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3464 area_vol[iel]=INTERP_KERNEL::computeVolSurfOfCell2<int,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[iel+1]-ipt-1,coords,dim_space);
3467 std::transform(area_vol,area_vol+nbelem,area_vol,std::ptr_fun<double,double>(fabs));
3471 area_vol[0]=std::numeric_limits<double>::max();
3473 return field.retn();
3477 * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3479 * For 1D cells, the returned array contains lengths.<br>
3480 * For 2D cells, the returned array contains areas.<br>
3481 * For 3D cells, the returned array contains volumes.
3482 * This method avoids building explicitly a part of \a this mesh to perform the work.
3483 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3484 * orientation, i.e. the volume is always positive.
3485 * \param [in] begin - an array of cell ids of interest.
3486 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3487 * \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3488 * delete this array using decrRef() as it is no more needed.
3490 * \if ENABLE_EXAMPLES
3491 * \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3492 * \ref py_mcumesh_getPartMeasureField "Here is a Python example".
3494 * \sa getMeasureField()
3496 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const int *begin, const int *end) const
3498 std::string name="PartMeasureOfMesh_";
3500 int nbelem=(int)std::distance(begin,end);
3501 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3502 array->setName(name);
3503 array->alloc(nbelem,1);
3504 double *area_vol=array->getPointer();
3505 if(getMeshDimension()!=-1)
3508 INTERP_KERNEL::NormalizedCellType type;
3509 int dim_space=getSpaceDimension();
3510 const double *coords=getCoords()->getConstPointer();
3511 const int *connec=getNodalConnectivity()->getConstPointer();
3512 const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3513 for(const int *iel=begin;iel!=end;iel++)
3515 ipt=connec_index[*iel];
3516 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3517 *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<int,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3520 std::transform(array->getPointer(),area_vol,array->getPointer(),std::ptr_fun<double,double>(fabs));
3524 area_vol[0]=std::numeric_limits<double>::max();
3526 return array.retn();
3530 * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3531 * \a this one. The returned field contains the dual cell volume for each corresponding
3532 * node in \a this mesh. In other words, the field returns the getMeasureField() of
3533 * the dual mesh in P1 sens of \a this.<br>
3534 * For 1D cells, the returned field contains lengths.<br>
3535 * For 2D cells, the returned field contains areas.<br>
3536 * For 3D cells, the returned field contains volumes.
3537 * This method is useful to check "P1*" conservative interpolators.
3538 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3539 * orientation, i.e. the volume is always positive.
3540 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3541 * nodes and one time. The caller is to delete this array using decrRef() as
3542 * it is no more needed.
3544 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3546 MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3547 std::string name="MeasureOnNodeOfMesh_";
3549 int nbNodes=getNumberOfNodes();
3550 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3551 double cst=1./((double)getMeshDimension()+1.);
3552 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3553 array->alloc(nbNodes,1);
3554 double *valsToFill=array->getPointer();
3555 std::fill(valsToFill,valsToFill+nbNodes,0.);
3556 const double *values=tmp->getArray()->getConstPointer();
3557 MCAuto<DataArrayInt> da=DataArrayInt::New();
3558 MCAuto<DataArrayInt> daInd=DataArrayInt::New();
3559 getReverseNodalConnectivity(da,daInd);
3560 const int *daPtr=da->getConstPointer();
3561 const int *daIPtr=daInd->getConstPointer();
3562 for(int i=0;i<nbNodes;i++)
3563 for(const int *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3564 valsToFill[i]+=cst*values[*cell];
3566 ret->setArray(array);
3571 * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3572 * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3573 * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3574 * and are normalized.
3575 * <br> \a this can be either
3576 * - a 2D mesh in 2D or 3D space or
3577 * - an 1D mesh in 2D space.
3579 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3580 * cells and one time. The caller is to delete this field using decrRef() as
3581 * it is no more needed.
3582 * \throw If the nodal connectivity of cells is not defined.
3583 * \throw If the coordinates array is not set.
3584 * \throw If the mesh dimension is not set.
3585 * \throw If the mesh and space dimension is not as specified above.
3587 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3589 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3590 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3591 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3592 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3593 int nbOfCells=getNumberOfCells();
3594 int nbComp=getMeshDimension()+1;
3595 array->alloc(nbOfCells,nbComp);
3596 double *vals=array->getPointer();
3597 const int *connI=_nodal_connec_index->getConstPointer();
3598 const int *conn=_nodal_connec->getConstPointer();
3599 const double *coords=_coords->getConstPointer();
3600 if(getMeshDimension()==2)
3602 if(getSpaceDimension()==3)
3604 MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3605 const double *locPtr=loc->getConstPointer();
3606 for(int i=0;i<nbOfCells;i++,vals+=3)
3608 int offset=connI[i];
3609 INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3610 double n=INTERP_KERNEL::norm<3>(vals);
3611 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3616 MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3617 const double *isAbsPtr=isAbs->getArray()->begin();
3618 for(int i=0;i<nbOfCells;i++,isAbsPtr++)
3619 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3622 else//meshdimension==1
3625 for(int i=0;i<nbOfCells;i++)
3627 int offset=connI[i];
3628 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3629 double n=INTERP_KERNEL::norm<2>(tmp);
3630 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3635 ret->setArray(array);
3637 ret->synchronizeTimeWithSupport();
3642 * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3643 * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3644 * and are normalized.
3645 * <br> \a this can be either
3646 * - a 2D mesh in 2D or 3D space or
3647 * - an 1D mesh in 2D space.
3649 * This method avoids building explicitly a part of \a this mesh to perform the work.
3650 * \param [in] begin - an array of cell ids of interest.
3651 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3652 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3653 * cells and one time. The caller is to delete this field using decrRef() as
3654 * it is no more needed.
3655 * \throw If the nodal connectivity of cells is not defined.
3656 * \throw If the coordinates array is not set.
3657 * \throw If the mesh dimension is not set.
3658 * \throw If the mesh and space dimension is not as specified above.
3659 * \sa buildOrthogonalField()
3661 * \if ENABLE_EXAMPLES
3662 * \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3663 * \ref py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3666 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const int *begin, const int *end) const
3668 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3669 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3670 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3671 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3672 std::size_t nbelems=std::distance(begin,end);
3673 int nbComp=getMeshDimension()+1;
3674 array->alloc((int)nbelems,nbComp);
3675 double *vals=array->getPointer();
3676 const int *connI=_nodal_connec_index->getConstPointer();
3677 const int *conn=_nodal_connec->getConstPointer();
3678 const double *coords=_coords->getConstPointer();
3679 if(getMeshDimension()==2)
3681 if(getSpaceDimension()==3)
3683 MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3684 const double *locPtr=loc->getConstPointer();
3685 for(const int *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3687 int offset=connI[*i];
3688 INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3689 double n=INTERP_KERNEL::norm<3>(vals);
3690 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3695 for(std::size_t i=0;i<nbelems;i++)
3696 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3699 else//meshdimension==1
3702 for(const int *i=begin;i!=end;i++)
3704 int offset=connI[*i];
3705 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3706 double n=INTERP_KERNEL::norm<2>(tmp);
3707 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3712 ret->setArray(array);
3714 ret->synchronizeTimeWithSupport();
3719 * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3720 * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3721 * and are \b not normalized.
3722 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3723 * cells and one time. The caller is to delete this field using decrRef() as
3724 * it is no more needed.
3725 * \throw If the nodal connectivity of cells is not defined.
3726 * \throw If the coordinates array is not set.
3727 * \throw If \a this->getMeshDimension() != 1.
3728 * \throw If \a this mesh includes cells of type other than SEG2.
3730 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3732 if(getMeshDimension()!=1)
3733 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3734 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3735 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3736 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3737 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3738 int nbOfCells=getNumberOfCells();
3739 int spaceDim=getSpaceDimension();
3740 array->alloc(nbOfCells,spaceDim);
3741 double *pt=array->getPointer();
3742 const double *coo=getCoords()->getConstPointer();
3743 std::vector<int> conn;
3745 for(int i=0;i<nbOfCells;i++)
3748 getNodeIdsOfCell(i,conn);
3749 pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3751 ret->setArray(array);
3753 ret->synchronizeTimeWithSupport();
3758 * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3759 * returns a new DataArrayInt, of length equal to the number of 2D cells in the result
3760 * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3761 * from. If a result face is shared by two 3D cells, then the face in included twice in
3763 * \param [in] origin - 3 components of a point defining location of the plane.
3764 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3765 * must be greater than 1e-6.
3766 * \param [in] eps - half-thickness of the plane.
3767 * \param [out] cellIds - a new instance of DataArrayInt holding ids of 3D cells
3768 * producing correspondent 2D cells. The caller is to delete this array
3769 * using decrRef() as it is no more needed.
3770 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3771 * not share the node coordinates array with \a this mesh. The caller is to
3772 * delete this mesh using decrRef() as it is no more needed.
3773 * \throw If the coordinates array is not set.
3774 * \throw If the nodal connectivity of cells is not defined.
3775 * \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3776 * \throw If magnitude of \a vec is less than 1e-6.
3777 * \throw If the plane does not intersect any 3D cell of \a this mesh.
3778 * \throw If \a this includes quadratic cells.
3780 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3782 checkFullyDefined();
3783 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3784 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3785 MCAuto<DataArrayInt> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3786 if(candidates->empty())
3787 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3788 std::vector<int> nodes;
3789 DataArrayInt *cellIds1D=0;
3790 MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3791 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3792 MCAuto<DataArrayInt> desc1=DataArrayInt::New(),desc2=DataArrayInt::New();
3793 MCAuto<DataArrayInt> descIndx1=DataArrayInt::New(),descIndx2=DataArrayInt::New();
3794 MCAuto<DataArrayInt> revDesc1=DataArrayInt::New(),revDesc2=DataArrayInt::New();
3795 MCAuto<DataArrayInt> revDescIndx1=DataArrayInt::New(),revDescIndx2=DataArrayInt::New();
3796 MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3797 revDesc2=0; revDescIndx2=0;
3798 MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3799 revDesc1=0; revDescIndx1=0;
3800 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3801 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3803 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3804 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3806 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3807 std::vector< std::pair<int,int> > cut3DSurf(mDesc2->getNumberOfCells());
3808 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3809 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3810 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3811 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New());
3812 connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3813 subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3814 if(cellIds2->empty())
3815 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3816 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3817 ret->setCoords(mDesc1->getCoords());
3818 ret->setConnectivity(conn,connI,true);
3819 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3824 * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3825 addition to the mesh, returns a new DataArrayInt, 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
3826 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3828 * \param [in] origin - 3 components of a point defining location of the plane.
3829 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3830 * must be greater than 1e-6.
3831 * \param [in] eps - half-thickness of the plane.
3832 * \param [out] cellIds - a new instance of DataArrayInt holding ids of faces
3833 * producing correspondent segments. The caller is to delete this array
3834 * using decrRef() as it is no more needed.
3835 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3836 * mesh in 3D space. This mesh does not share the node coordinates array with
3837 * \a this mesh. The caller is to delete this mesh using decrRef() as it is
3839 * \throw If the coordinates array is not set.
3840 * \throw If the nodal connectivity of cells is not defined.
3841 * \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3842 * \throw If magnitude of \a vec is less than 1e-6.
3843 * \throw If the plane does not intersect any 2D cell of \a this mesh.
3844 * \throw If \a this includes quadratic cells.
3846 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3848 checkFullyDefined();
3849 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3850 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3851 MCAuto<DataArrayInt> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3852 if(candidates->empty())
3853 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3854 std::vector<int> nodes;
3855 DataArrayInt *cellIds1D=0;
3856 MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3857 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3858 MCAuto<DataArrayInt> desc1=DataArrayInt::New();
3859 MCAuto<DataArrayInt> descIndx1=DataArrayInt::New();
3860 MCAuto<DataArrayInt> revDesc1=DataArrayInt::New();
3861 MCAuto<DataArrayInt> revDescIndx1=DataArrayInt::New();
3862 MCAuto<MEDCouplingUMesh> mDesc1=subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3863 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3864 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3866 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3867 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3869 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3870 int ncellsSub=subMesh->getNumberOfCells();
3871 std::vector< std::pair<int,int> > cut3DSurf(ncellsSub);
3872 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3873 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3874 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3875 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New()); connI->pushBackSilent(0);
3877 const int *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3878 const int *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3879 for(int i=0;i<ncellsSub;i++)
3881 if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3883 if(cut3DSurf[i].first!=-2)
3885 conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3886 connI->pushBackSilent(conn->getNumberOfTuples());
3887 cellIds2->pushBackSilent(i);
3891 int cellId3DSurf=cut3DSurf[i].second;
3892 int offset=nodalI[cellId3DSurf]+1;
3893 int nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3894 for(int j=0;j<nbOfEdges;j++)
3896 conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3897 connI->pushBackSilent(conn->getNumberOfTuples());
3898 cellIds2->pushBackSilent(cellId3DSurf);
3903 if(cellIds2->empty())
3904 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3905 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3906 ret->setCoords(mDesc1->getCoords());
3907 ret->setConnectivity(conn,connI,true);
3908 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3913 * Finds cells whose bounding boxes intersect a given plane.
3914 * \param [in] origin - 3 components of a point defining location of the plane.
3915 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3916 * must be greater than 1e-6.
3917 * \param [in] eps - half-thickness of the plane.
3918 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of the found
3919 * cells. The caller is to delete this array using decrRef() as it is no more
3921 * \throw If the coordinates array is not set.
3922 * \throw If the nodal connectivity of cells is not defined.
3923 * \throw If \a this->getSpaceDimension() != 3.
3924 * \throw If magnitude of \a vec is less than 1e-6.
3925 * \sa buildSlice3D()
3927 DataArrayInt *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
3929 checkFullyDefined();
3930 if(getSpaceDimension()!=3)
3931 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
3932 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
3934 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
3936 vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
3937 double angle=acos(vec[2]/normm);
3938 MCAuto<DataArrayInt> cellIds;
3942 MCAuto<DataArrayDouble> coo=_coords->deepCopy();
3943 double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
3944 if(normm2/normm>1e-6)
3945 MEDCouplingPointSet::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer());
3946 MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
3948 mw->getBoundingBox(bbox);
3949 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3950 cellIds=mw->getCellsInBoundingBox(bbox,eps);
3954 getBoundingBox(bbox);
3955 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3956 cellIds=getCellsInBoundingBox(bbox,eps);
3958 return cellIds.retn();
3962 * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
3963 * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
3964 * No consideration of coordinate is done by this method.
3965 * 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)
3966 * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be usefull.
3968 bool MEDCouplingUMesh::isContiguous1D() const
3970 if(getMeshDimension()!=1)
3971 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
3972 int nbCells=getNumberOfCells();
3974 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
3975 const int *connI=_nodal_connec_index->getConstPointer();
3976 const int *conn=_nodal_connec->getConstPointer();
3977 int ref=conn[connI[0]+2];
3978 for(int i=1;i<nbCells;i++)
3980 if(conn[connI[i]+1]!=ref)
3982 ref=conn[connI[i]+2];
3988 * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
3989 * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
3990 * \param pt reference point of the line
3991 * \param v normalized director vector of the line
3992 * \param eps max precision before throwing an exception
3993 * \param res output of size this->getNumberOfCells
3995 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
3997 if(getMeshDimension()!=1)
3998 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
3999 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
4000 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
4001 if(getSpaceDimension()!=3)
4002 throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
4003 MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
4004 const double *fPtr=f->getArray()->getConstPointer();
4006 for(int i=0;i<getNumberOfCells();i++)
4008 const double *tmp1=fPtr+3*i;
4009 tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
4010 tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
4011 tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
4012 double n1=INTERP_KERNEL::norm<3>(tmp);
4013 n1/=INTERP_KERNEL::norm<3>(tmp1);
4015 throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
4017 const double *coo=getCoords()->getConstPointer();
4018 for(int i=0;i<getNumberOfNodes();i++)
4020 std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
4021 std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
4022 res[i]=std::accumulate(tmp,tmp+3,0.);
4027 * 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.
4028 * \a this is expected to be a mesh so that its space dimension is equal to its
4029 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4030 * 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).
4032 * 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
4033 * 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).
4034 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4036 * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
4037 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4039 * \param [in] ptBg the start pointer (included) of the coordinates of the point
4040 * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
4041 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4042 * \return the positive value of the distance.
4043 * \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
4045 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
4047 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, int& cellId) const
4049 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4050 if(meshDim!=spaceDim-1)
4051 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
4052 if(meshDim!=2 && meshDim!=1)
4053 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
4054 checkFullyDefined();
4055 if((int)std::distance(ptBg,ptEnd)!=spaceDim)
4056 { 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().c_str()); }
4057 DataArrayInt *ret1=0;
4058 MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,C_DEALLOC,1,spaceDim);
4059 MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
4060 MCAuto<DataArrayInt> ret1Safe(ret1);
4061 cellId=*ret1Safe->begin();
4062 return *ret0->begin();
4066 * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
4067 * to \a this and the first \a cellId in \a this corresponding to the returned distance.
4068 * 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
4069 * 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).
4070 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4072 * \a this is expected to be a mesh so that its space dimension is equal to its
4073 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4074 * 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).
4076 * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
4077 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4079 * \param [in] pts the list of points in which each tuple represents a point
4080 * \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.
4081 * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
4082 * \throw if number of components of \a pts is not equal to the space dimension.
4083 * \throw if mesh dimension of \a this is not equal to space dimension - 1.
4084 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
4086 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayInt *& cellIds) const
4089 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
4090 pts->checkAllocated();
4091 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4092 if(meshDim!=spaceDim-1)
4093 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
4094 if(meshDim!=2 && meshDim!=1)
4095 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
4096 if(pts->getNumberOfComponents()!=spaceDim)
4098 std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
4099 throw INTERP_KERNEL::Exception(oss.str().c_str());
4101 checkFullyDefined();
4102 int nbCells=getNumberOfCells();
4104 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
4105 int nbOfPts=pts->getNumberOfTuples();
4106 MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
4107 MCAuto<DataArrayInt> ret1=DataArrayInt::New(); ret1->alloc(nbOfPts,1);
4108 const int *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
4109 double *ret0Ptr=ret0->getPointer(); int *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
4110 MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
4111 const double *bbox(bboxArr->begin());
4116 BBTreeDst<3> myTree(bbox,0,0,nbCells);
4117 for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
4119 double x=std::numeric_limits<double>::max();
4120 std::vector<int> elems;
4121 myTree.getMinDistanceOfMax(ptsPtr,x);
4122 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4123 DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4129 BBTreeDst<2> myTree(bbox,0,0,nbCells);
4130 for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4132 double x=std::numeric_limits<double>::max();
4133 std::vector<int> elems;
4134 myTree.getMinDistanceOfMax(ptsPtr,x);
4135 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4136 DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4141 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4143 cellIds=ret1.retn();
4150 * \param [in] pt the start pointer (included) of the coordinates of the point
4151 * \param [in] cellIdsBg the start pointer (included) of cellIds
4152 * \param [in] cellIdsEnd the end pointer (excluded) of cellIds
4153 * \param [in] nc nodal connectivity
4154 * \param [in] ncI nodal connectivity index
4155 * \param [in,out] ret0 the min distance between \a this and the external input point
4156 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4157 * \sa MEDCouplingUMesh::distanceToPoint, MEDCouplingUMesh::distanceToPoints
4159 void MEDCouplingUMesh::DistanceToPoint3DSurfAlg(const double *pt, const int *cellIdsBg, const int *cellIdsEnd, const double *coords, const int *nc, const int *ncI, double& ret0, int& cellId)
4162 ret0=std::numeric_limits<double>::max();
4163 for(const int *zeCell=cellIdsBg;zeCell!=cellIdsEnd;zeCell++)
4165 switch((INTERP_KERNEL::NormalizedCellType)nc[ncI[*zeCell]])
4167 case INTERP_KERNEL::NORM_TRI3:
4169 double tmp=INTERP_KERNEL::DistanceFromPtToTriInSpaceDim3(pt,coords+3*nc[ncI[*zeCell]+1],coords+3*nc[ncI[*zeCell]+2],coords+3*nc[ncI[*zeCell]+3]);
4171 { ret0=tmp; cellId=*zeCell; }
4174 case INTERP_KERNEL::NORM_QUAD4:
4175 case INTERP_KERNEL::NORM_POLYGON:
4177 double tmp=INTERP_KERNEL::DistanceFromPtToPolygonInSpaceDim3(pt,nc+ncI[*zeCell]+1,nc+ncI[*zeCell+1],coords);
4179 { ret0=tmp; cellId=*zeCell; }
4183 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint3DSurfAlg : not managed cell type ! Supporting TRI3, QUAD4 and POLYGON !");
4189 * \param [in] pt the start pointer (included) of the coordinates of the point
4190 * \param [in] cellIdsBg the start pointer (included) of cellIds
4191 * \param [in] cellIdsEnd the end pointer (excluded) of cellIds
4192 * \param [in] nc nodal connectivity
4193 * \param [in] ncI nodal connectivity index
4194 * \param [in,out] ret0 the min distance between \a this and the external input point
4195 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4196 * \sa MEDCouplingUMesh::distanceToPoint, MEDCouplingUMesh::distanceToPoints
4198 void MEDCouplingUMesh::DistanceToPoint2DCurveAlg(const double *pt, const int *cellIdsBg, const int *cellIdsEnd, const double *coords, const int *nc, const int *ncI, double& ret0, int& cellId)
4201 ret0=std::numeric_limits<double>::max();
4202 for(const int *zeCell=cellIdsBg;zeCell!=cellIdsEnd;zeCell++)
4204 switch((INTERP_KERNEL::NormalizedCellType)nc[ncI[*zeCell]])
4206 case INTERP_KERNEL::NORM_SEG2:
4208 std::size_t uselessEntry=0;
4209 double tmp=INTERP_KERNEL::SquareDistanceFromPtToSegInSpaceDim2(pt,coords+2*nc[ncI[*zeCell]+1],coords+2*nc[ncI[*zeCell]+2],uselessEntry);
4212 { ret0=tmp; cellId=*zeCell; }
4216 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint2DCurveAlg : not managed cell type ! Supporting SEG2 !");
4223 * Finds cells in contact with a ball (i.e. a point with precision).
4224 * 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.
4225 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4227 * \warning This method is suitable if the caller intends to evaluate only one
4228 * point, for more points getCellsContainingPoints() is recommended as it is
4230 * \param [in] pos - array of coordinates of the ball central point.
4231 * \param [in] eps - ball radius.
4232 * \return int - a smallest id of cells being in contact with the ball, -1 in case
4233 * if there are no such cells.
4234 * \throw If the coordinates array is not set.
4235 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4237 int MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4239 std::vector<int> elts;
4240 getCellsContainingPoint(pos,eps,elts);
4243 return elts.front();
4247 * Finds cells in contact with a ball (i.e. a point with precision).
4248 * 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.
4249 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4250 * \warning This method is suitable if the caller intends to evaluate only one
4251 * point, for more points getCellsContainingPoints() is recommended as it is
4253 * \param [in] pos - array of coordinates of the ball central point.
4254 * \param [in] eps - ball radius.
4255 * \param [out] elts - vector returning ids of the found cells. It is cleared
4256 * before inserting ids.
4257 * \throw If the coordinates array is not set.
4258 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4260 * \if ENABLE_EXAMPLES
4261 * \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4262 * \ref py_mcumesh_getCellsContainingPoint "Here is a Python example".
4265 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<int>& elts) const
4267 MCAuto<DataArrayInt> eltsUg,eltsIndexUg;
4268 getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4269 elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4274 namespace MEDCoupling
4276 template<const int SPACEDIMM>
4280 static const int MY_SPACEDIM=SPACEDIMM;
4281 static const int MY_MESHDIM=8;
4282 typedef int MyConnType;
4283 static const INTERP_KERNEL::NumberingPolicy My_numPol=INTERP_KERNEL::ALL_C_MODE;
4285 // useless, but for windows compilation ...
4286 const double* getCoordinatesPtr() const { return 0; }
4287 const int* getConnectivityPtr() const { return 0; }
4288 const int* getConnectivityIndexPtr() const { return 0; }
4289 INTERP_KERNEL::NormalizedCellType getTypeOfElement(int) const { return (INTERP_KERNEL::NormalizedCellType)0; }
4293 INTERP_KERNEL::Edge *MEDCouplingUMeshBuildQPFromEdge2(INTERP_KERNEL::NormalizedCellType typ, const int *bg, const double *coords2D, std::map< MCAuto<INTERP_KERNEL::Node>,int>& m)
4295 INTERP_KERNEL::Edge *ret(0);
4296 MCAuto<INTERP_KERNEL::Node> n0(new INTERP_KERNEL::Node(coords2D[2*bg[0]],coords2D[2*bg[0]+1])),n1(new INTERP_KERNEL::Node(coords2D[2*bg[1]],coords2D[2*bg[1]+1]));
4297 m[n0]=bg[0]; m[n1]=bg[1];
4300 case INTERP_KERNEL::NORM_SEG2:
4302 ret=new INTERP_KERNEL::EdgeLin(n0,n1);
4305 case INTERP_KERNEL::NORM_SEG3:
4307 INTERP_KERNEL::Node *n2(new INTERP_KERNEL::Node(coords2D[2*bg[2]],coords2D[2*bg[2]+1])); m[n2]=bg[2];
4308 INTERP_KERNEL::EdgeLin *e1(new INTERP_KERNEL::EdgeLin(n0,n2)),*e2(new INTERP_KERNEL::EdgeLin(n2,n1));
4309 INTERP_KERNEL::SegSegIntersector inters(*e1,*e2);
4310 // is the SEG3 degenerated, and thus can be reduced to a SEG2?
4311 bool colinearity(inters.areColinears());
4312 delete e1; delete e2;
4314 { ret=new INTERP_KERNEL::EdgeLin(n0,n1); }
4316 { ret=new INTERP_KERNEL::EdgeArcCircle(n0,n2,n1); }
4320 throw INTERP_KERNEL::Exception("MEDCouplingUMeshBuildQPFromEdge2 : Expecting a mesh with spaceDim==2 and meshDim==1 !");
4325 INTERP_KERNEL::Edge *MEDCouplingUMeshBuildQPFromEdge(INTERP_KERNEL::NormalizedCellType typ, std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >& mapp2, const int *bg)
4327 INTERP_KERNEL::Edge *ret=0;
4330 case INTERP_KERNEL::NORM_SEG2:
4332 ret=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[1]].first);
4335 case INTERP_KERNEL::NORM_SEG3:
4337 INTERP_KERNEL::EdgeLin *e1=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[2]].first);
4338 INTERP_KERNEL::EdgeLin *e2=new INTERP_KERNEL::EdgeLin(mapp2[bg[2]].first,mapp2[bg[1]].first);
4339 INTERP_KERNEL::SegSegIntersector inters(*e1,*e2);
4340 // is the SEG3 degenerated, and thus can be reduced to a SEG2?
4341 bool colinearity=inters.areColinears();
4342 delete e1; delete e2;
4344 ret=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[1]].first);
4346 ret=new INTERP_KERNEL::EdgeArcCircle(mapp2[bg[0]].first,mapp2[bg[2]].first,mapp2[bg[1]].first);
4347 mapp2[bg[2]].second=false;
4351 throw INTERP_KERNEL::Exception("MEDCouplingUMeshBuildQPFromEdge : Expecting a mesh with spaceDim==2 and meshDim==1 !");
4357 * This method creates a sub mesh in Geometric2D DS. The sub mesh is composed by the sub set of cells in 'candidates' taken from
4358 * the global mesh 'mDesc'.
4359 * The input mesh 'mDesc' must be so that mDim==1 and spaceDim==2.
4360 * 'mapp' returns a mapping between local numbering in submesh (represented by a Node*) and the global node numbering in 'mDesc'.
4362 INTERP_KERNEL::QuadraticPolygon *MEDCouplingUMeshBuildQPFromMesh(const MEDCouplingUMesh *mDesc, const std::vector<int>& candidates,
4363 std::map<INTERP_KERNEL::Node *,int>& mapp)
4366 std::map<int, std::pair<INTERP_KERNEL::Node *,bool> > mapp2;//bool is for a flag specifying if node is boundary (true) or only a middle for SEG3.
4367 const double *coo=mDesc->getCoords()->getConstPointer();
4368 const int *c=mDesc->getNodalConnectivity()->getConstPointer();
4369 const int *cI=mDesc->getNodalConnectivityIndex()->getConstPointer();
4371 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
4372 s.insert(c+cI[*it]+1,c+cI[(*it)+1]);
4373 for(std::set<int>::const_iterator it2=s.begin();it2!=s.end();it2++)
4375 INTERP_KERNEL::Node *n=new INTERP_KERNEL::Node(coo[2*(*it2)],coo[2*(*it2)+1]);
4376 mapp2[*it2]=std::pair<INTERP_KERNEL::Node *,bool>(n,true);
4378 INTERP_KERNEL::QuadraticPolygon *ret=new INTERP_KERNEL::QuadraticPolygon;
4379 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
4381 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[*it]];
4382 ret->pushBack(MEDCouplingUMeshBuildQPFromEdge(typ,mapp2,c+cI[*it]+1));
4384 for(std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >::const_iterator it2=mapp2.begin();it2!=mapp2.end();it2++)
4386 if((*it2).second.second)
4387 mapp[(*it2).second.first]=(*it2).first;
4388 ((*it2).second.first)->decrRef();
4393 INTERP_KERNEL::Node *MEDCouplingUMeshBuildQPNode(int nodeId, const double *coo1, int offset1, const double *coo2, int offset2, const std::vector<double>& addCoo)
4397 int locId=nodeId-offset2;
4398 return new INTERP_KERNEL::Node(addCoo[2*locId],addCoo[2*locId+1]);
4402 int locId=nodeId-offset1;
4403 return new INTERP_KERNEL::Node(coo2[2*locId],coo2[2*locId+1]);
4405 return new INTERP_KERNEL::Node(coo1[2*nodeId],coo1[2*nodeId+1]);
4409 * Construct a mapping between set of Nodes and the standart MEDCoupling connectivity format (c, cI).
4411 void MEDCouplingUMeshBuildQPFromMesh3(const double *coo1, int offset1, const double *coo2, int offset2, const std::vector<double>& addCoo,
4412 const int *desc1Bg, const int *desc1End, const std::vector<std::vector<int> >& intesctEdges1,
4413 /*output*/std::map<INTERP_KERNEL::Node *,int>& mapp, std::map<int,INTERP_KERNEL::Node *>& mappRev)
4415 for(const int *desc1=desc1Bg;desc1!=desc1End;desc1++)
4417 int eltId1=abs(*desc1)-1;
4418 for(std::vector<int>::const_iterator it1=intesctEdges1[eltId1].begin();it1!=intesctEdges1[eltId1].end();it1++)
4420 std::map<int,INTERP_KERNEL::Node *>::const_iterator it=mappRev.find(*it1);
4421 if(it==mappRev.end())
4423 INTERP_KERNEL::Node *node=MEDCouplingUMeshBuildQPNode(*it1,coo1,offset1,coo2,offset2,addCoo);
4434 template<int SPACEDIM>
4435 void MEDCouplingUMesh::getCellsContainingPointsAlg(const double *coords, const double *pos, int nbOfPoints,
4436 double eps, MCAuto<DataArrayInt>& elts, MCAuto<DataArrayInt>& eltsIndex) const
4438 elts=DataArrayInt::New(); eltsIndex=DataArrayInt::New(); eltsIndex->alloc(nbOfPoints+1,1); eltsIndex->setIJ(0,0,0); elts->alloc(0,1);
4439 int *eltsIndexPtr(eltsIndex->getPointer());
4440 MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree(eps));
4441 const double *bbox(bboxArr->begin());
4442 int nbOfCells=getNumberOfCells();
4443 const int *conn=_nodal_connec->getConstPointer();
4444 const int *connI=_nodal_connec_index->getConstPointer();
4445 double bb[2*SPACEDIM];
4446 BBTree<SPACEDIM,int> myTree(&bbox[0],0,0,nbOfCells,-eps);
4447 for(int i=0;i<nbOfPoints;i++)
4449 eltsIndexPtr[i+1]=eltsIndexPtr[i];
4450 for(int j=0;j<SPACEDIM;j++)
4452 bb[2*j]=pos[SPACEDIM*i+j];
4453 bb[2*j+1]=pos[SPACEDIM*i+j];
4455 std::vector<int> candidates;
4456 myTree.getIntersectingElems(bb,candidates);
4457 for(std::vector<int>::const_iterator iter=candidates.begin();iter!=candidates.end();iter++)
4459 int sz(connI[(*iter)+1]-connI[*iter]-1);
4460 INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[connI[*iter]]);
4462 if(ct!=INTERP_KERNEL::NORM_POLYGON && ct!=INTERP_KERNEL::NORM_QPOLYG)
4463 status=INTERP_KERNEL::PointLocatorAlgos<DummyClsMCUG<SPACEDIM> >::isElementContainsPoint(pos+i*SPACEDIM,ct,coords,conn+connI[*iter]+1,sz,eps);
4467 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPointsAlg : not implemented yet for POLYGON and QPOLYGON in spaceDim 3 !");
4468 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
4469 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
4470 std::vector<INTERP_KERNEL::Node *> nodes(sz);
4471 INTERP_KERNEL::QuadraticPolygon *pol(0);
4472 for(int j=0;j<sz;j++)
4474 int nodeId(conn[connI[*iter]+1+j]);
4475 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*SPACEDIM],coords[nodeId*SPACEDIM+1]);
4477 if(!INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic())
4478 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
4480 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
4481 INTERP_KERNEL::Node *n(new INTERP_KERNEL::Node(pos[i*SPACEDIM],pos[i*SPACEDIM+1]));
4482 double a(0.),b(0.),c(0.);
4483 a=pol->normalizeMe(b,c); n->applySimilarity(b,c,a);
4484 status=pol->isInOrOut2(n);
4485 delete pol; n->decrRef();
4489 eltsIndexPtr[i+1]++;
4490 elts->pushBackSilent(*iter);
4496 * Finds cells in contact with several balls (i.e. points with precision).
4497 * This method is an extension of getCellContainingPoint() and
4498 * getCellsContainingPoint() for the case of multiple points.
4499 * 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.
4500 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4501 * \param [in] pos - an array of coordinates of points in full interlace mode :
4502 * X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4503 * this->getSpaceDimension() * \a nbOfPoints
4504 * \param [in] nbOfPoints - number of points to locate within \a this mesh.
4505 * \param [in] eps - radius of balls (i.e. the precision).
4506 * \param [out] elts - vector returning ids of found cells.
4507 * \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4508 * dividing cell ids in \a elts into groups each referring to one
4509 * point. Its every element (except the last one) is an index pointing to the
4510 * first id of a group of cells. For example cells in contact with the *i*-th
4511 * point are described by following range of indices:
4512 * [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4513 * \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4514 * Number of cells in contact with the *i*-th point is
4515 * \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4516 * \throw If the coordinates array is not set.
4517 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4519 * \if ENABLE_EXAMPLES
4520 * \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4521 * \ref py_mcumesh_getCellsContainingPoints "Here is a Python example".
4524 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, int nbOfPoints, double eps,
4525 MCAuto<DataArrayInt>& elts, MCAuto<DataArrayInt>& eltsIndex) const
4527 int spaceDim=getSpaceDimension();
4528 int mDim=getMeshDimension();
4533 const double *coords=_coords->getConstPointer();
4534 getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4541 throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4543 else if(spaceDim==2)
4547 const double *coords=_coords->getConstPointer();
4548 getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4551 throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4553 else if(spaceDim==1)
4557 const double *coords=_coords->getConstPointer();
4558 getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4561 throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4564 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4568 * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4569 * least two its edges intersect each other anywhere except their extremities. An
4570 * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4571 * \param [in,out] cells - a vector returning ids of the found cells. It is not
4572 * cleared before filling in.
4573 * \param [in] eps - precision.
4574 * \throw If \a this->getMeshDimension() != 2.
4575 * \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4577 void MEDCouplingUMesh::checkButterflyCells(std::vector<int>& cells, double eps) const
4579 const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4580 if(getMeshDimension()!=2)
4581 throw INTERP_KERNEL::Exception(msg);
4582 int spaceDim=getSpaceDimension();
4583 if(spaceDim!=2 && spaceDim!=3)
4584 throw INTERP_KERNEL::Exception(msg);
4585 const int *conn=_nodal_connec->getConstPointer();
4586 const int *connI=_nodal_connec_index->getConstPointer();
4587 int nbOfCells=getNumberOfCells();
4588 std::vector<double> cell2DinS2;
4589 for(int i=0;i<nbOfCells;i++)
4591 int offset=connI[i];
4592 int nbOfNodesForCell=connI[i+1]-offset-1;
4593 if(nbOfNodesForCell<=3)
4595 bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4596 project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4597 if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4604 * This method is typically requested to unbutterfly 2D linear cells in \b this.
4606 * 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.
4607 * 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.
4609 * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4610 * This convex envelop is computed using Jarvis march algorithm.
4611 * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4612 * 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)
4613 * 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.
4615 * \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.
4616 * \sa MEDCouplingUMesh::colinearize2D
4618 DataArrayInt *MEDCouplingUMesh::convexEnvelop2D()
4620 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4621 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D works only for meshDim=2 and spaceDim=2 !");
4622 checkFullyDefined();
4623 const double *coords=getCoords()->getConstPointer();
4624 int nbOfCells=getNumberOfCells();
4625 MCAuto<DataArrayInt> nodalConnecIndexOut=DataArrayInt::New();
4626 nodalConnecIndexOut->alloc(nbOfCells+1,1);
4627 MCAuto<DataArrayInt> nodalConnecOut(DataArrayInt::New());
4628 int *workIndexOut=nodalConnecIndexOut->getPointer();
4630 const int *nodalConnecIn=_nodal_connec->getConstPointer();
4631 const int *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4632 std::set<INTERP_KERNEL::NormalizedCellType> types;
4633 MCAuto<DataArrayInt> isChanged(DataArrayInt::New());
4634 isChanged->alloc(0,1);
4635 for(int i=0;i<nbOfCells;i++,workIndexOut++)
4637 int pos=nodalConnecOut->getNumberOfTuples();
4638 if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4639 isChanged->pushBackSilent(i);
4640 types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4641 workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4643 if(isChanged->empty())
4645 setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4647 return isChanged.retn();
4651 * This method is \b NOT const because it can modify \a this.
4652 * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4653 * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4654 * \param policy specifies the type of extrusion chosen:
4655 * - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4656 * will be repeated to build each level
4657 * - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4658 * 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
4659 * 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
4661 * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4663 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4665 checkFullyDefined();
4666 mesh1D->checkFullyDefined();
4667 if(!mesh1D->isContiguous1D())
4668 throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4669 if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4670 throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4671 if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4672 throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4673 if(mesh1D->getMeshDimension()!=1)
4674 throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4676 if(isPresenceOfQuadratic())
4678 if(mesh1D->isFullyQuadratic())
4681 throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4683 int oldNbOfNodes(getNumberOfNodes());
4684 MCAuto<DataArrayDouble> newCoords;
4689 newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4694 newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4698 throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4700 setCoords(newCoords);
4701 MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4707 * This method works on a 3D curve linear mesh that is to say (meshDim==1 and spaceDim==3).
4708 * If it is not the case an exception will be thrown.
4709 * This method is non const because the coordinate of \a this can be appended with some new points issued from
4710 * intersection of plane defined by ('origin','vec').
4711 * This method has one in/out parameter : 'cut3DCurve'.
4712 * Param 'cut3DCurve' is expected to be of size 'this->getNumberOfCells()'. For each i in [0,'this->getNumberOfCells()')
4713 * if cut3DCurve[i]==-2, it means that for cell #i in \a this nothing has been detected previously.
4714 * if cut3DCurve[i]==-1, it means that cell#i has been already detected to be fully part of plane defined by ('origin','vec').
4715 * This method will throw an exception if \a this contains a non linear segment.
4717 void MEDCouplingUMesh::split3DCurveWithPlane(const double *origin, const double *vec, double eps, std::vector<int>& cut3DCurve)
4719 checkFullyDefined();
4720 if(getMeshDimension()!=1 || getSpaceDimension()!=3)
4721 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane works on umeshes with meshdim equal to 1 and spaceDim equal to 3 !");
4722 int ncells=getNumberOfCells();
4723 int nnodes=getNumberOfNodes();
4724 double vec2[3],vec3[3],vec4[3];
4725 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
4727 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
4728 vec2[0]=vec[0]/normm; vec2[1]=vec[1]/normm; vec2[2]=vec[2]/normm;
4729 const int *conn=_nodal_connec->getConstPointer();
4730 const int *connI=_nodal_connec_index->getConstPointer();
4731 const double *coo=_coords->getConstPointer();
4732 std::vector<double> addCoo;
4733 for(int i=0;i<ncells;i++)
4735 if(conn[connI[i]]==(int)INTERP_KERNEL::NORM_SEG2)
4737 if(cut3DCurve[i]==-2)
4739 int st=conn[connI[i]+1],endd=conn[connI[i]+2];
4740 vec3[0]=coo[3*endd]-coo[3*st]; vec3[1]=coo[3*endd+1]-coo[3*st+1]; vec3[2]=coo[3*endd+2]-coo[3*st+2];
4741 double normm2=sqrt(vec3[0]*vec3[0]+vec3[1]*vec3[1]+vec3[2]*vec3[2]);
4742 double colin=std::abs((vec3[0]*vec2[0]+vec3[1]*vec2[1]+vec3[2]*vec2[2])/normm2);
4743 if(colin>eps)//if colin<=eps -> current SEG2 is colinear to the input plane
4745 const double *st2=coo+3*st;
4746 vec4[0]=st2[0]-origin[0]; vec4[1]=st2[1]-origin[1]; vec4[2]=st2[2]-origin[2];
4747 double pos=-(vec4[0]*vec2[0]+vec4[1]*vec2[1]+vec4[2]*vec2[2])/((vec3[0]*vec2[0]+vec3[1]*vec2[1]+vec3[2]*vec2[2]));
4748 if(pos>eps && pos<1-eps)
4750 int nNode=((int)addCoo.size())/3;
4751 vec4[0]=st2[0]+pos*vec3[0]; vec4[1]=st2[1]+pos*vec3[1]; vec4[2]=st2[2]+pos*vec3[2];
4752 addCoo.insert(addCoo.end(),vec4,vec4+3);
4753 cut3DCurve[i]=nnodes+nNode;
4759 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane : this method is only available for linear cell (NORM_SEG2) !");
4763 int newNbOfNodes=nnodes+((int)addCoo.size())/3;
4764 MCAuto<DataArrayDouble> coo2=DataArrayDouble::New();
4765 coo2->alloc(newNbOfNodes,3);
4766 double *tmp=coo2->getPointer();
4767 tmp=std::copy(_coords->begin(),_coords->end(),tmp);
4768 std::copy(addCoo.begin(),addCoo.end(),tmp);
4769 DataArrayDouble::SetArrayIn(coo2,_coords);
4774 * This method incarnates the policy 0 for MEDCouplingUMesh::buildExtrudedMesh method.
4775 * \param mesh1D is the input 1D mesh used for translation computation.
4776 * \return newCoords new coords filled by this method.
4778 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslation(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4780 int oldNbOfNodes=getNumberOfNodes();
4781 int nbOf1DCells=mesh1D->getNumberOfCells();
4782 int spaceDim=getSpaceDimension();
4783 DataArrayDouble *ret=DataArrayDouble::New();
4784 std::vector<bool> isQuads;
4785 int nbOfLevsInVec=isQuad?2*nbOf1DCells+1:nbOf1DCells+1;
4786 ret->alloc(oldNbOfNodes*nbOfLevsInVec,spaceDim);
4787 double *retPtr=ret->getPointer();
4788 const double *coords=getCoords()->getConstPointer();
4789 double *work=std::copy(coords,coords+spaceDim*oldNbOfNodes,retPtr);
4791 std::vector<double> c;
4795 for(int i=0;i<nbOf1DCells;i++)
4798 mesh1D->getNodeIdsOfCell(i,v);
4800 mesh1D->getCoordinatesOfNode(v[isQuad?2:1],c);
4801 mesh1D->getCoordinatesOfNode(v[0],c);
4802 std::transform(c.begin(),c.begin()+spaceDim,c.begin()+spaceDim,vec,std::minus<double>());
4803 for(int j=0;j<oldNbOfNodes;j++)
4804 work=std::transform(vec,vec+spaceDim,retPtr+spaceDim*(i*oldNbOfNodes+j),work,std::plus<double>());
4808 mesh1D->getCoordinatesOfNode(v[1],c);
4809 mesh1D->getCoordinatesOfNode(v[0],c);
4810 std::transform(c.begin(),c.begin()+spaceDim,c.begin()+spaceDim,vec,std::minus<double>());
4811 for(int j=0;j<oldNbOfNodes;j++)
4812 work=std::transform(vec,vec+spaceDim,retPtr+spaceDim*(i*oldNbOfNodes+j),work,std::plus<double>());
4815 ret->copyStringInfoFrom(*getCoords());
4820 * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4821 * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4822 * \return newCoords new coords filled by this method.
4824 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4826 if(mesh1D->getSpaceDimension()==2)
4827 return fillExtCoordsUsingTranslAndAutoRotation2D(mesh1D,isQuad);
4828 if(mesh1D->getSpaceDimension()==3)
4829 return fillExtCoordsUsingTranslAndAutoRotation3D(mesh1D,isQuad);
4830 throw INTERP_KERNEL::Exception("Not implemented rotation and translation alg. for spacedim other than 2 and 3 !");
4834 * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4835 * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4836 * \return newCoords new coords filled by this method.
4838 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4841 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D : not implemented for quadratic cells !");
4842 int oldNbOfNodes=getNumberOfNodes();
4843 int nbOf1DCells=mesh1D->getNumberOfCells();
4845 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D : impossible to detect any angle of rotation ! Change extrusion policy 1->0 !");
4846 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
4847 int nbOfLevsInVec=nbOf1DCells+1;
4848 ret->alloc(oldNbOfNodes*nbOfLevsInVec,2);
4849 double *retPtr=ret->getPointer();
4850 retPtr=std::copy(getCoords()->getConstPointer(),getCoords()->getConstPointer()+getCoords()->getNbOfElems(),retPtr);
4851 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
4852 MCAuto<DataArrayDouble> tmp2=getCoords()->deepCopy();
4853 tmp->setCoords(tmp2);
4854 const double *coo1D=mesh1D->getCoords()->getConstPointer();
4855 const int *conn1D=mesh1D->getNodalConnectivity()->getConstPointer();
4856 const int *connI1D=mesh1D->getNodalConnectivityIndex()->getConstPointer();
4857 for(int i=1;i<nbOfLevsInVec;i++)
4859 const double *begin=coo1D+2*conn1D[connI1D[i-1]+1];
4860 const double *end=coo1D+2*conn1D[connI1D[i-1]+2];
4861 const double *third=i+1<nbOfLevsInVec?coo1D+2*conn1D[connI1D[i]+2]:coo1D+2*conn1D[connI1D[i-2]+1];
4862 const double vec[2]={end[0]-begin[0],end[1]-begin[1]};
4863 tmp->translate(vec);
4864 double tmp3[2],radius,alpha,alpha0;
4865 const double *p0=i+1<nbOfLevsInVec?begin:third;
4866 const double *p1=i+1<nbOfLevsInVec?end:begin;
4867 const double *p2=i+1<nbOfLevsInVec?third:end;
4868 INTERP_KERNEL::EdgeArcCircle::GetArcOfCirclePassingThru(p0,p1,p2,tmp3,radius,alpha,alpha0);
4869 double cosangle=i+1<nbOfLevsInVec?(p0[0]-tmp3[0])*(p1[0]-tmp3[0])+(p0[1]-tmp3[1])*(p1[1]-tmp3[1]):(p2[0]-tmp3[0])*(p1[0]-tmp3[0])+(p2[1]-tmp3[1])*(p1[1]-tmp3[1]);
4870 double angle=acos(cosangle/(radius*radius));
4871 tmp->rotate(end,0,angle);
4872 retPtr=std::copy(tmp2->getConstPointer(),tmp2->getConstPointer()+tmp2->getNbOfElems(),retPtr);
4878 * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4879 * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4880 * \return newCoords new coords filled by this method.
4882 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4885 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D : not implemented for quadratic cells !");
4886 int oldNbOfNodes=getNumberOfNodes();
4887 int nbOf1DCells=mesh1D->getNumberOfCells();
4889 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D : impossible to detect any angle of rotation ! Change extrusion policy 1->0 !");
4890 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
4891 int nbOfLevsInVec=nbOf1DCells+1;
4892 ret->alloc(oldNbOfNodes*nbOfLevsInVec,3);
4893 double *retPtr=ret->getPointer();
4894 retPtr=std::copy(getCoords()->getConstPointer(),getCoords()->getConstPointer()+getCoords()->getNbOfElems(),retPtr);
4895 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
4896 MCAuto<DataArrayDouble> tmp2=getCoords()->deepCopy();
4897 tmp->setCoords(tmp2);
4898 const double *coo1D=mesh1D->getCoords()->getConstPointer();
4899 const int *conn1D=mesh1D->getNodalConnectivity()->getConstPointer();
4900 const int *connI1D=mesh1D->getNodalConnectivityIndex()->getConstPointer();
4901 for(int i=1;i<nbOfLevsInVec;i++)
4903 const double *begin=coo1D+3*conn1D[connI1D[i-1]+1];
4904 const double *end=coo1D+3*conn1D[connI1D[i-1]+2];
4905 const double *third=i+1<nbOfLevsInVec?coo1D+3*conn1D[connI1D[i]+2]:coo1D+3*conn1D[connI1D[i-2]+1];
4906 const double vec[3]={end[0]-begin[0],end[1]-begin[1],end[2]-begin[2]};
4907 tmp->translate(vec);
4908 double tmp3[2],radius,alpha,alpha0;
4909 const double *p0=i+1<nbOfLevsInVec?begin:third;
4910 const double *p1=i+1<nbOfLevsInVec?end:begin;
4911 const double *p2=i+1<nbOfLevsInVec?third:end;
4912 double vecPlane[3]={
4913 (p1[1]-p0[1])*(p2[2]-p1[2])-(p1[2]-p0[2])*(p2[1]-p1[1]),
4914 (p1[2]-p0[2])*(p2[0]-p1[0])-(p1[0]-p0[0])*(p2[2]-p1[2]),
4915 (p1[0]-p0[0])*(p2[1]-p1[1])-(p1[1]-p0[1])*(p2[0]-p1[0]),
4917 double norm=sqrt(vecPlane[0]*vecPlane[0]+vecPlane[1]*vecPlane[1]+vecPlane[2]*vecPlane[2]);
4920 vecPlane[0]/=norm; vecPlane[1]/=norm; vecPlane[2]/=norm;
4921 double norm2=sqrt(vecPlane[0]*vecPlane[0]+vecPlane[1]*vecPlane[1]);
4922 double vec2[2]={vecPlane[1]/norm2,-vecPlane[0]/norm2};
4924 double c2=cos(asin(s2));
4926 {vec2[0]*vec2[0]*(1-c2)+c2, vec2[0]*vec2[1]*(1-c2), vec2[1]*s2},
4927 {vec2[0]*vec2[1]*(1-c2), vec2[1]*vec2[1]*(1-c2)+c2, -vec2[0]*s2},
4928 {-vec2[1]*s2, vec2[0]*s2, c2}
4930 double p0r[3]={m[0][0]*p0[0]+m[0][1]*p0[1]+m[0][2]*p0[2], m[1][0]*p0[0]+m[1][1]*p0[1]+m[1][2]*p0[2], m[2][0]*p0[0]+m[2][1]*p0[1]+m[2][2]*p0[2]};
4931 double p1r[3]={m[0][0]*p1[0]+m[0][1]*p1[1]+m[0][2]*p1[2], m[1][0]*p1[0]+m[1][1]*p1[1]+m[1][2]*p1[2], m[2][0]*p1[0]+m[2][1]*p1[1]+m[2][2]*p1[2]};
4932 double p2r[3]={m[0][0]*p2[0]+m[0][1]*p2[1]+m[0][2]*p2[2], m[1][0]*p2[0]+m[1][1]*p2[1]+m[1][2]*p2[2], m[2][0]*p2[0]+m[2][1]*p2[1]+m[2][2]*p2[2]};
4933 INTERP_KERNEL::EdgeArcCircle::GetArcOfCirclePassingThru(p0r,p1r,p2r,tmp3,radius,alpha,alpha0);
4934 double cosangle=i+1<nbOfLevsInVec?(p0r[0]-tmp3[0])*(p1r[0]-tmp3[0])+(p0r[1]-tmp3[1])*(p1r[1]-tmp3[1]):(p2r[0]-tmp3[0])*(p1r[0]-tmp3[0])+(p2r[1]-tmp3[1])*(p1r[1]-tmp3[1]);
4935 double angle=acos(cosangle/(radius*radius));
4936 tmp->rotate(end,vecPlane,angle);
4938 retPtr=std::copy(tmp2->getConstPointer(),tmp2->getConstPointer()+tmp2->getNbOfElems(),retPtr);
4944 * This method is private because not easy to use for end user. This method is const contrary to
4945 * MEDCouplingUMesh::buildExtrudedMesh method because this->_coords are expected to contain
4946 * the coords sorted slice by slice.
4947 * \param isQuad specifies presence of quadratic cells.
4949 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMeshFromThisLowLev(int nbOfNodesOf1Lev, bool isQuad) const
4951 int nbOf1DCells(getNumberOfNodes()/nbOfNodesOf1Lev-1);
4952 int nbOf2DCells(getNumberOfCells());
4953 int nbOf3DCells(nbOf2DCells*nbOf1DCells);
4954 MEDCouplingUMesh *ret(MEDCouplingUMesh::New("Extruded",getMeshDimension()+1));
4955 const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
4956 MCAuto<DataArrayInt> newConn(DataArrayInt::New()),newConnI(DataArrayInt::New());
4957 newConnI->alloc(nbOf3DCells+1,1);
4958 int *newConnIPtr(newConnI->getPointer());
4960 std::vector<int> newc;
4961 for(int j=0;j<nbOf2DCells;j++)
4963 AppendExtrudedCell(conn+connI[j],conn+connI[j+1],nbOfNodesOf1Lev,isQuad,newc);
4964 *newConnIPtr++=(int)newc.size();
4966 newConn->alloc((int)(newc.size())*nbOf1DCells,1);
4967 int *newConnPtr(newConn->getPointer());
4968 int deltaPerLev(isQuad?2*nbOfNodesOf1Lev:nbOfNodesOf1Lev);
4969 newConnIPtr=newConnI->getPointer();
4970 for(int iz=0;iz<nbOf1DCells;iz++)
4973 std::transform(newConnIPtr+1,newConnIPtr+1+nbOf2DCells,newConnIPtr+1+iz*nbOf2DCells,std::bind2nd(std::plus<int>(),newConnIPtr[iz*nbOf2DCells]));
4974 const int *posOfTypeOfCell(newConnIPtr);
4975 for(std::vector<int>::const_iterator iter=newc.begin();iter!=newc.end();iter++,newConnPtr++)
4977 int icell((int)(iter-newc.begin()));//std::distance unfortunately cannot been called here in C++98
4978 if(icell!=*posOfTypeOfCell)
4981 *newConnPtr=(*iter)+iz*deltaPerLev;
4992 ret->setConnectivity(newConn,newConnI,true);
4993 ret->setCoords(getCoords());
4998 * Checks if \a this mesh is constituted by only quadratic cells.
4999 * \return bool - \c true if there are only quadratic cells in \a this mesh.
5000 * \throw If the coordinates array is not set.
5001 * \throw If the nodal connectivity of cells is not defined.
5003 bool MEDCouplingUMesh::isFullyQuadratic() const
5005 checkFullyDefined();
5007 int nbOfCells=getNumberOfCells();
5008 for(int i=0;i<nbOfCells && ret;i++)
5010 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5011 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5012 ret=cm.isQuadratic();
5018 * Checks if \a this mesh includes any quadratic cell.
5019 * \return bool - \c true if there is at least one quadratic cells in \a this mesh.
5020 * \throw If the coordinates array is not set.
5021 * \throw If the nodal connectivity of cells is not defined.
5023 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
5025 checkFullyDefined();
5027 int nbOfCells=getNumberOfCells();
5028 for(int i=0;i<nbOfCells && !ret;i++)
5030 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5031 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5032 ret=cm.isQuadratic();
5038 * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
5039 * this mesh, it remains unchanged.
5040 * \throw If the coordinates array is not set.
5041 * \throw If the nodal connectivity of cells is not defined.
5043 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
5045 checkFullyDefined();
5046 int nbOfCells=getNumberOfCells();
5048 const int *iciptr=_nodal_connec_index->getConstPointer();
5049 for(int i=0;i<nbOfCells;i++)
5051 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5052 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5053 if(cm.isQuadratic())
5055 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
5056 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
5057 if(!cml.isDynamic())
5058 delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
5060 delta+=(iciptr[i+1]-iciptr[i]-1)/2;
5065 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5066 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5067 const int *icptr=_nodal_connec->getConstPointer();
5068 newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
5069 newConnI->alloc(nbOfCells+1,1);
5070 int *ocptr=newConn->getPointer();
5071 int *ociptr=newConnI->getPointer();
5074 for(int i=0;i<nbOfCells;i++,ociptr++)
5076 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
5077 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5078 if(!cm.isQuadratic())
5080 _types.insert(type);
5081 ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
5082 ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
5086 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
5087 _types.insert(typel);
5088 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
5089 int newNbOfNodes=cml.getNumberOfNodes();
5091 newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
5092 *ocptr++=(int)typel;
5093 ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
5094 ociptr[1]=ociptr[0]+newNbOfNodes+1;
5097 setConnectivity(newConn,newConnI,false);
5101 * This method converts all linear cell in \a this to quadratic one.
5102 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
5103 * 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)
5104 * 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.
5105 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
5106 * end of the existing coordinates.
5108 * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
5109 * corresponding quadratic cells. 1 is those creating the 'most' complex.
5110 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5112 * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
5114 * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
5116 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
5118 DataArrayInt *conn=0,*connI=0;
5119 DataArrayDouble *coords=0;
5120 std::set<INTERP_KERNEL::NormalizedCellType> types;
5121 checkFullyDefined();
5122 MCAuto<DataArrayInt> ret,connSafe,connISafe;
5123 MCAuto<DataArrayDouble> coordsSafe;
5124 int meshDim=getMeshDimension();
5125 switch(conversionType)
5131 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
5132 connSafe=conn; connISafe=connI; coordsSafe=coords;
5135 ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
5136 connSafe=conn; connISafe=connI; coordsSafe=coords;
5139 ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
5140 connSafe=conn; connISafe=connI; coordsSafe=coords;
5143 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
5151 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
5152 connSafe=conn; connISafe=connI; coordsSafe=coords;
5155 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
5156 connSafe=conn; connISafe=connI; coordsSafe=coords;
5159 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
5160 connSafe=conn; connISafe=connI; coordsSafe=coords;
5163 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
5168 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
5170 setConnectivity(connSafe,connISafe,false);
5172 setCoords(coordsSafe);
5177 * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
5178 * so that the number of cells remains the same. Quadratic faces are converted to
5179 * polygons. This method works only for 2D meshes in
5180 * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
5181 * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
5182 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5183 * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
5184 * a polylinized edge constituting the input polygon.
5185 * \throw If the coordinates array is not set.
5186 * \throw If the nodal connectivity of cells is not defined.
5187 * \throw If \a this->getMeshDimension() != 2.
5188 * \throw If \a this->getSpaceDimension() != 2.
5190 void MEDCouplingUMesh::tessellate2D(double eps)
5192 int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
5194 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
5198 return tessellate2DCurveInternal(eps);
5200 return tessellate2DInternal(eps);
5202 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
5206 * Tessellates \a this 1D mesh in 2D space by dividing not straight quadratic edges.
5207 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5208 * \param [in] eps - specifies the maximal angle (in radian) between 2 sub-edges of
5209 * a sub-divided edge.
5210 * \throw If the coordinates array is not set.
5211 * \throw If the nodal connectivity of cells is not defined.
5212 * \throw If \a this->getMeshDimension() != 1.
5213 * \throw If \a this->getSpaceDimension() != 2.
5218 * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
5219 * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
5220 * The nodes to be added in those 2D cells are defined by the pair of \a nodeIdsToAdd and \a nodeIdsIndexToAdd.
5221 * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
5222 * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
5223 * This method can be seen as the opposite method of colinearize2D.
5224 * 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
5225 * to avoid to modify the numbering of existing nodes.
5227 * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
5228 * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
5229 * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
5230 * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
5231 * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
5232 * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
5233 * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
5235 * \sa buildDescendingConnectivity2
5237 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayInt *nodeIdsToAdd, const DataArrayInt *nodeIdsIndexToAdd, const DataArrayInt *edgeIdsToBeSplit,
5238 const MEDCouplingUMesh *mesh1Desc, const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *revDesc, const DataArrayInt *revDescI)
5240 if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
5241 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
5242 nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
5243 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
5244 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
5245 if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
5246 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
5247 //DataArrayInt *out0(0),*outi0(0);
5248 //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
5249 //MCAuto<DataArrayInt> out0s(out0),outi0s(outi0);
5250 //out0s=out0s->buildUnique(); out0s->sort(true);
5255 * Implementes \a conversionType 0 for meshes with meshDim = 1, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5256 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5257 * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5259 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic1D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5261 MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5262 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5263 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5264 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5265 int nbOfCells=getNumberOfCells();
5266 int nbOfNodes=getNumberOfNodes();
5267 const int *cPtr=_nodal_connec->getConstPointer();
5268 const int *icPtr=_nodal_connec_index->getConstPointer();
5269 int lastVal=0,offset=nbOfNodes;
5270 for(int i=0;i<nbOfCells;i++,icPtr++)
5272 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5273 if(type==INTERP_KERNEL::NORM_SEG2)
5275 types.insert(INTERP_KERNEL::NORM_SEG3);
5276 newConn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG3);
5277 newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[0]+3);
5278 newConn->pushBackSilent(offset++);
5280 newConnI->pushBackSilent(lastVal);
5281 ret->pushBackSilent(i);
5286 lastVal+=(icPtr[1]-icPtr[0]);
5287 newConnI->pushBackSilent(lastVal);
5288 newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5291 MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5292 coords=DataArrayDouble::Aggregate(getCoords(),tmp); conn=newConn.retn(); connI=newConnI.retn();
5296 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic2DAnd3D0(const MEDCouplingUMesh *m1D, const DataArrayInt *desc, const DataArrayInt *descI, DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5298 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5299 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5300 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5302 const int *descPtr(desc->begin()),*descIPtr(descI->begin());
5303 DataArrayInt *conn1D=0,*conn1DI=0;
5304 std::set<INTERP_KERNEL::NormalizedCellType> types1D;
5305 DataArrayDouble *coordsTmp=0;
5306 MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=0;
5307 MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5308 MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5309 const int *c1DPtr=conn1D->begin();
5310 const int *c1DIPtr=conn1DI->begin();
5311 int nbOfCells=getNumberOfCells();
5312 const int *cPtr=_nodal_connec->getConstPointer();
5313 const int *icPtr=_nodal_connec_index->getConstPointer();
5315 for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++)
5317 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5318 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5319 if(!cm.isQuadratic())
5321 INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType();
5322 types.insert(typ2); newConn->pushBackSilent(typ2);
5323 newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5324 for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5325 newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5326 lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0]);
5327 newConnI->pushBackSilent(lastVal);
5328 ret->pushBackSilent(i);
5333 lastVal+=(icPtr[1]-icPtr[0]);
5334 newConnI->pushBackSilent(lastVal);
5335 newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5338 conn=newConn.retn(); connI=newConnI.retn(); coords=coordsTmpSafe.retn();
5343 * Implementes \a conversionType 0 for meshes with meshDim = 2, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5344 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5345 * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5347 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic2D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5349 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5350 MCAuto<MEDCouplingUMesh> m1D=buildDescendingConnectivity(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5351 return convertLinearCellsToQuadratic2DAnd3D0(m1D,desc,descI,conn,connI,coords,types);
5354 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic2D1(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5356 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5357 MCAuto<MEDCouplingUMesh> m1D=buildDescendingConnectivity(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5359 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5360 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5361 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5363 MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5364 const int *descPtr(desc->begin()),*descIPtr(descI->begin());
5365 DataArrayInt *conn1D=0,*conn1DI=0;
5366 std::set<INTERP_KERNEL::NormalizedCellType> types1D;
5367 DataArrayDouble *coordsTmp=0;
5368 MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=0;
5369 MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5370 MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5371 const int *c1DPtr=conn1D->begin();
5372 const int *c1DIPtr=conn1DI->begin();
5373 int nbOfCells=getNumberOfCells();
5374 const int *cPtr=_nodal_connec->getConstPointer();
5375 const int *icPtr=_nodal_connec_index->getConstPointer();
5376 int lastVal=0,offset=coordsTmpSafe->getNumberOfTuples();
5377 for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++)
5379 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5380 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5381 if(!cm.isQuadratic())
5383 INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType2();
5384 types.insert(typ2); newConn->pushBackSilent(typ2);
5385 newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5386 for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5387 newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5388 newConn->pushBackSilent(offset+ret->getNumberOfTuples());
5389 lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0])+1;
5390 newConnI->pushBackSilent(lastVal);
5391 ret->pushBackSilent(i);
5396 lastVal+=(icPtr[1]-icPtr[0]);
5397 newConnI->pushBackSilent(lastVal);
5398 newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5401 MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5402 coords=DataArrayDouble::Aggregate(coordsTmpSafe,tmp); conn=newConn.retn(); connI=newConnI.retn();
5407 * Implementes \a conversionType 0 for meshes with meshDim = 3, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5408 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5409 * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5411 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic3D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5413 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5414 MCAuto<MEDCouplingUMesh> m1D=explode3DMeshTo1D(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5415 return convertLinearCellsToQuadratic2DAnd3D0(m1D,desc,descI,conn,connI,coords,types);
5418 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic3D1(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5420 MCAuto<DataArrayInt> desc2(DataArrayInt::New()),desc2I(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5421 MCAuto<MEDCouplingUMesh> m2D=buildDescendingConnectivityGen<MinusOneSonsGeneratorBiQuadratic>(desc2,desc2I,tmp2,tmp3,MEDCouplingFastNbrer); tmp2=0; tmp3=0;
5422 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),desc1I(DataArrayInt::New()),tmp4(DataArrayInt::New()),tmp5(DataArrayInt::New());
5423 MCAuto<MEDCouplingUMesh> m1D=explode3DMeshTo1D(desc1,desc1I,tmp4,tmp5); tmp4=0; tmp5=0;
5425 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5426 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5427 MCAuto<DataArrayInt> ret=DataArrayInt::New(),ret2=DataArrayInt::New(); ret->alloc(0,1); ret2->alloc(0,1);
5429 MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5430 const int *descPtr(desc1->begin()),*descIPtr(desc1I->begin()),*desc2Ptr(desc2->begin()),*desc2IPtr(desc2I->begin());
5431 DataArrayInt *conn1D=0,*conn1DI=0,*conn2D=0,*conn2DI=0;
5432 std::set<INTERP_KERNEL::NormalizedCellType> types1D,types2D;
5433 DataArrayDouble *coordsTmp=0,*coordsTmp2=0;
5434 MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=DataArrayInt::New(); ret1D->alloc(0,1);
5435 MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5436 MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5437 MCAuto<DataArrayInt> ret2D=m2D->convertLinearCellsToQuadratic2D1(conn2D,conn2DI,coordsTmp2,types2D); ret2D=DataArrayInt::New(); ret2D->alloc(0,1);
5438 MCAuto<DataArrayDouble> coordsTmp2Safe(coordsTmp2);
5439 MCAuto<DataArrayInt> conn2DSafe(conn2D),conn2DISafe(conn2DI);
5440 const int *c1DPtr=conn1D->begin(),*c1DIPtr=conn1DI->begin(),*c2DPtr=conn2D->begin(),*c2DIPtr=conn2DI->begin();
5441 int nbOfCells=getNumberOfCells();
5442 const int *cPtr=_nodal_connec->getConstPointer();
5443 const int *icPtr=_nodal_connec_index->getConstPointer();
5444 int lastVal=0,offset=coordsTmpSafe->getNumberOfTuples();
5445 for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++,desc2IPtr++)
5447 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5448 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5449 if(!cm.isQuadratic())
5451 INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType2();
5452 if(typ2==INTERP_KERNEL::NORM_ERROR)
5454 std::ostringstream oss; oss << "MEDCouplingUMesh::convertLinearCellsToQuadratic3D1 : On cell #" << i << " the linear cell type does not support advanced quadratization !";
5455 throw INTERP_KERNEL::Exception(oss.str().c_str());
5457 types.insert(typ2); newConn->pushBackSilent(typ2);
5458 newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5459 for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5460 newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5461 for(const int *d=desc2Ptr+desc2IPtr[0];d!=desc2Ptr+desc2IPtr[1];d++)
5463 int nodeId2=c2DPtr[c2DIPtr[(*d)+1]-1];
5464 int tmpPos=newConn->getNumberOfTuples();
5465 newConn->pushBackSilent(nodeId2);
5466 ret2D->pushBackSilent(nodeId2); ret1D->pushBackSilent(tmpPos);
5468 newConn->pushBackSilent(offset+ret->getNumberOfTuples());
5469 lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0])+(desc2IPtr[1]-desc2IPtr[0])+1;
5470 newConnI->pushBackSilent(lastVal);
5471 ret->pushBackSilent(i);
5476 lastVal+=(icPtr[1]-icPtr[0]);
5477 newConnI->pushBackSilent(lastVal);
5478 newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5481 MCAuto<DataArrayInt> diffRet2D=ret2D->getDifferentValues();
5482 MCAuto<DataArrayInt> o2nRet2D=diffRet2D->invertArrayN2O2O2N(coordsTmp2Safe->getNumberOfTuples());
5483 coordsTmp2Safe=coordsTmp2Safe->selectByTupleId(diffRet2D->begin(),diffRet2D->end());
5484 MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5485 std::vector<const DataArrayDouble *> v(3); v[0]=coordsTmpSafe; v[1]=coordsTmp2Safe; v[2]=tmp;
5486 int *c=newConn->getPointer();
5487 const int *cI(newConnI->begin());
5488 for(const int *elt=ret1D->begin();elt!=ret1D->end();elt++)
5489 c[*elt]=o2nRet2D->getIJ(c[*elt],0)+offset;
5490 offset=coordsTmp2Safe->getNumberOfTuples();
5491 for(const int *elt=ret->begin();elt!=ret->end();elt++)
5492 c[cI[(*elt)+1]-1]+=offset;
5493 coords=DataArrayDouble::Aggregate(v); conn=newConn.retn(); connI=newConnI.retn();
5498 * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
5499 * In addition, returns an array mapping new cells to old ones. <br>
5500 * This method typically increases the number of cells in \a this mesh
5501 * but the number of nodes remains \b unchanged.
5502 * That's why the 3D splitting policies
5503 * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
5504 * \param [in] policy - specifies a pattern used for splitting.
5505 * The semantic of \a policy is:
5506 * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
5507 * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
5508 * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8 into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
5509 * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8 into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
5512 * \return DataArrayInt * - a new instance of DataArrayInt holding, for each new cell,
5513 * an id of old cell producing it. The caller is to delete this array using
5514 * decrRef() as it is no more needed.
5516 * \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
5517 * \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
5518 * and \a this->getMeshDimension() != 3.
5519 * \throw If \a policy is not one of the four discussed above.
5520 * \throw If the nodal connectivity of cells is not defined.
5521 * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
5523 DataArrayInt *MEDCouplingUMesh::simplexize(int policy)
5528 return simplexizePol0();
5530 return simplexizePol1();
5531 case (int) INTERP_KERNEL::PLANAR_FACE_5:
5532 return simplexizePlanarFace5();
5533 case (int) INTERP_KERNEL::PLANAR_FACE_6:
5534 return simplexizePlanarFace6();
5536 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)");
5541 * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
5542 * - 1D: INTERP_KERNEL::NORM_SEG2
5543 * - 2D: INTERP_KERNEL::NORM_TRI3
5544 * - 3D: INTERP_KERNEL::NORM_TETRA4.
5546 * This method is useful for users that need to use P1 field services as
5547 * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
5548 * All these methods need mesh support containing only simplex cells.
5549 * \return bool - \c true if there are only simplex cells in \a this mesh.
5550 * \throw If the coordinates array is not set.
5551 * \throw If the nodal connectivity of cells is not defined.
5552 * \throw If \a this->getMeshDimension() < 1.
5554 bool MEDCouplingUMesh::areOnlySimplexCells() const
5556 checkFullyDefined();
5557 int mdim=getMeshDimension();
5558 if(mdim<1 || mdim>3)
5559 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
5560 int nbCells=getNumberOfCells();
5561 const int *conn=_nodal_connec->getConstPointer();
5562 const int *connI=_nodal_connec_index->getConstPointer();
5563 for(int i=0;i<nbCells;i++)
5565 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5573 * This method implements policy 0 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5575 DataArrayInt *MEDCouplingUMesh::simplexizePol0()
5577 checkConnectivityFullyDefined();
5578 if(getMeshDimension()!=2)
5579 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePol0 : this policy is only available for mesh with meshdim == 2 !");
5580 int nbOfCells=getNumberOfCells();
5581 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5582 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_QUAD4);
5583 ret->alloc(nbOfCells+nbOfCutCells,1);
5584 if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5585 int *retPt=ret->getPointer();
5586 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5587 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5588 newConnI->alloc(nbOfCells+nbOfCutCells+1,1);
5589 newConn->alloc(getNodalConnectivityArrayLen()+3*nbOfCutCells,1);
5590 int *pt=newConn->getPointer();
5591 int *ptI=newConnI->getPointer();
5593 const int *oldc=_nodal_connec->getConstPointer();
5594 const int *ci=_nodal_connec_index->getConstPointer();
5595 for(int i=0;i<nbOfCells;i++,ci++)
5597 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_QUAD4)
5599 const int tmp[8]={(int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+2],oldc[ci[0]+3],
5600 (int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+3],oldc[ci[0]+4]};
5601 pt=std::copy(tmp,tmp+8,pt);
5610 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5611 ptI[1]=ptI[0]+ci[1]-ci[0];
5616 _nodal_connec->decrRef();
5617 _nodal_connec=newConn.retn();
5618 _nodal_connec_index->decrRef();
5619 _nodal_connec_index=newConnI.retn();
5626 * This method implements policy 1 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5628 DataArrayInt *MEDCouplingUMesh::simplexizePol1()
5630 checkConnectivityFullyDefined();
5631 if(getMeshDimension()!=2)
5632 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePol0 : this policy is only available for mesh with meshdim == 2 !");
5633 int nbOfCells=getNumberOfCells();
5634 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5635 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_QUAD4);
5636 ret->alloc(nbOfCells+nbOfCutCells,1);
5637 if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5638 int *retPt=ret->getPointer();
5639 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5640 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5641 newConnI->alloc(nbOfCells+nbOfCutCells+1,1);
5642 newConn->alloc(getNodalConnectivityArrayLen()+3*nbOfCutCells,1);
5643 int *pt=newConn->getPointer();
5644 int *ptI=newConnI->getPointer();
5646 const int *oldc=_nodal_connec->getConstPointer();
5647 const int *ci=_nodal_connec_index->getConstPointer();
5648 for(int i=0;i<nbOfCells;i++,ci++)
5650 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_QUAD4)
5652 const int tmp[8]={(int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+2],oldc[ci[0]+4],
5653 (int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+2],oldc[ci[0]+3],oldc[ci[0]+4]};
5654 pt=std::copy(tmp,tmp+8,pt);
5663 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5664 ptI[1]=ptI[0]+ci[1]-ci[0];
5669 _nodal_connec->decrRef();
5670 _nodal_connec=newConn.retn();
5671 _nodal_connec_index->decrRef();
5672 _nodal_connec_index=newConnI.retn();
5679 * This method implements policy INTERP_KERNEL::PLANAR_FACE_5 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5681 DataArrayInt *MEDCouplingUMesh::simplexizePlanarFace5()
5683 checkConnectivityFullyDefined();
5684 if(getMeshDimension()!=3)
5685 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePlanarFace5 : this policy is only available for mesh with meshdim == 3 !");
5686 int nbOfCells=getNumberOfCells();
5687 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5688 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_HEXA8);
5689 ret->alloc(nbOfCells+4*nbOfCutCells,1);
5690 if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5691 int *retPt=ret->getPointer();
5692 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5693 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5694 newConnI->alloc(nbOfCells+4*nbOfCutCells+1,1);
5695 newConn->alloc(getNodalConnectivityArrayLen()+16*nbOfCutCells,1);//21
5696 int *pt=newConn->getPointer();
5697 int *ptI=newConnI->getPointer();
5699 const int *oldc=_nodal_connec->getConstPointer();
5700 const int *ci=_nodal_connec_index->getConstPointer();
5701 for(int i=0;i<nbOfCells;i++,ci++)
5703 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_HEXA8)
5705 for(int j=0;j<5;j++,pt+=5,ptI++)
5707 pt[0]=(int)INTERP_KERNEL::NORM_TETRA4;
5708 pt[1]=oldc[ci[0]+INTERP_KERNEL::SPLIT_NODES_5_WO[4*j+0]+1]; pt[2]=oldc[ci[0]+INTERP_KERNEL::SPLIT_NODES_5_WO[4*j+1]+1]; pt[3]=oldc[ci[0]+INTERP_KERNEL::SPLIT_NODES_5_WO[4*j+2]+1]; pt[4]=oldc[ci[0]+INTERP_KERNEL::SPLIT_NODES_5_WO[4*j+3]+1];
5715 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5716 ptI[1]=ptI[0]+ci[1]-ci[0];
5721 _nodal_connec->decrRef();
5722 _nodal_connec=newConn.retn();
5723 _nodal_connec_index->decrRef();
5724 _nodal_connec_index=newConnI.retn();
5731 * This method implements policy INTERP_KERNEL::PLANAR_FACE_6 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5733 DataArrayInt *MEDCouplingUMesh::simplexizePlanarFace6()
5735 checkConnectivityFullyDefined();
5736 if(getMeshDimension()!=3)
5737 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePlanarFace6 : this policy is only available for mesh with meshdim == 3 !");
5738 int nbOfCells=getNumberOfCells();
5739 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5740 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_HEXA8);
5741 ret->alloc(nbOfCells+5*nbOfCutCells,1);
5742 if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5743 int *retPt=ret->getPointer();
5744 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5745 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5746 newConnI->alloc(nbOfCells+5*nbOfCutCells+1,1);
5747 newConn->alloc(getNodalConnectivityArrayLen()+21*nbOfCutCells,1);
5748 int *pt=newConn->getPointer();
5749 int *ptI=newConnI->getPointer();
5751 const int *oldc=_nodal_connec->getConstPointer();
5752 const int *ci=_nodal_connec_index->getConstPointer();
5753 for(int i=0;i<nbOfCells;i++,ci++)
5755 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_HEXA8)
5757 for(int j=0;j<6;j++,pt+=5,ptI++)
5759 pt[0]=(int)INTERP_KERNEL::NORM_TETRA4;
5760 pt[1]=oldc[ci[0]+INTERP_KERNEL::SPLIT_NODES_6_WO[4*j+0]+1]; pt[2]=oldc[ci[0]+INTERP_KERNEL::SPLIT_NODES_6_WO[4*j+1]+1]; pt[3]=oldc[ci[0]+INTERP_KERNEL::SPLIT_NODES_6_WO[4*j+2]+1]; pt[4]=oldc[ci[0]+INTERP_KERNEL::SPLIT_NODES_6_WO[4*j+3]+1];
5767 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5768 ptI[1]=ptI[0]+ci[1]-ci[0];
5773 _nodal_connec->decrRef();
5774 _nodal_connec=newConn.retn();
5775 _nodal_connec_index->decrRef();
5776 _nodal_connec_index=newConnI.retn();
5783 * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
5784 * so that the number of cells remains the same. Quadratic faces are converted to
5785 * polygons. This method works only for 2D meshes in
5786 * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
5787 * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
5788 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5789 * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
5790 * a polylinized edge constituting the input polygon.
5791 * \throw If the coordinates array is not set.
5792 * \throw If the nodal connectivity of cells is not defined.
5793 * \throw If \a this->getMeshDimension() != 2.
5794 * \throw If \a this->getSpaceDimension() != 2.
5796 void MEDCouplingUMesh::tessellate2DInternal(double eps)
5798 checkFullyDefined();
5799 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
5800 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DInternal works on umeshes with meshdim equal to 2 and spaceDim equal to 2 too!");
5801 double epsa=fabs(eps);
5802 if(epsa<std::numeric_limits<double>::min())
5803 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DInternal : epsilon is null ! Please specify a higher epsilon. If too tiny it can lead to a huge amount of nodes and memory !");
5804 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
5805 MCAuto<MEDCouplingUMesh> mDesc(buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1));
5806 revDesc1=0; revDescIndx1=0;
5807 mDesc->tessellate2D(eps);
5808 subDivide2DMesh(mDesc->_nodal_connec->getConstPointer(),mDesc->_nodal_connec_index->getConstPointer(),desc1->getConstPointer(),descIndx1->getConstPointer());
5809 setCoords(mDesc->getCoords());
5813 * Tessellates \a this 1D mesh in 2D space by dividing not straight quadratic edges.
5814 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5815 * \param [in] eps - specifies the maximal angle (in radian) between 2 sub-edges of
5816 * a sub-divided edge.
5817 * \throw If the coordinates array is not set.
5818 * \throw If the nodal connectivity of cells is not defined.
5819 * \throw If \a this->getMeshDimension() != 1.
5820 * \throw If \a this->getSpaceDimension() != 2.
5822 void MEDCouplingUMesh::tessellate2DCurveInternal(double eps)
5824 checkFullyDefined();
5825 if(getMeshDimension()!=1 || getSpaceDimension()!=2)
5826 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DCurveInternal works on umeshes with meshdim equal to 1 and spaceDim equal to 2 too!");
5827 double epsa=fabs(eps);
5828 if(epsa<std::numeric_limits<double>::min())
5829 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DCurveInternal : epsilon is null ! Please specify a higher epsilon. If too tiny it can lead to a huge amount of nodes and memory !");
5830 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=1.e-10;
5831 int nbCells=getNumberOfCells();
5832 int nbNodes=getNumberOfNodes();
5833 const int *conn=_nodal_connec->getConstPointer();
5834 const int *connI=_nodal_connec_index->getConstPointer();
5835 const double *coords=_coords->getConstPointer();
5836 std::vector<double> addCoo;
5837 std::vector<int> newConn;//no direct DataArrayInt because interface with Geometric2D
5838 MCAuto<DataArrayInt> newConnI(DataArrayInt::New());
5839 newConnI->alloc(nbCells+1,1);
5840 int *newConnIPtr=newConnI->getPointer();
5843 INTERP_KERNEL::Node *tmp2[3];
5844 std::set<INTERP_KERNEL::NormalizedCellType> types;
5845 for(int i=0;i<nbCells;i++,newConnIPtr++)
5847 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5848 if(cm.isQuadratic())
5849 {//assert(connI[i+1]-connI[i]-1==3)
5850 tmp1[0]=conn[connI[i]+1+0]; tmp1[1]=conn[connI[i]+1+1]; tmp1[2]=conn[connI[i]+1+2];
5851 tmp2[0]=new INTERP_KERNEL::Node(coords[2*tmp1[0]],coords[2*tmp1[0]+1]);
5852 tmp2[1]=new INTERP_KERNEL::Node(coords[2*tmp1[1]],coords[2*tmp1[1]+1]);
5853 tmp2[2]=new INTERP_KERNEL::Node(coords[2*tmp1[2]],coords[2*tmp1[2]+1]);
5854 INTERP_KERNEL::EdgeArcCircle *eac=INTERP_KERNEL::EdgeArcCircle::BuildFromNodes(tmp2[0],tmp2[2],tmp2[1]);
5857 eac->tesselate(tmp1,nbNodes,epsa,newConn,addCoo);
5858 types.insert((INTERP_KERNEL::NormalizedCellType)newConn[newConnIPtr[0]]);
5860 newConnIPtr[1]=(int)newConn.size();
5864 types.insert(INTERP_KERNEL::NORM_SEG2);
5865 newConn.push_back(INTERP_KERNEL::NORM_SEG2);
5866 newConn.insert(newConn.end(),conn+connI[i]+1,conn+connI[i]+3);
5867 newConnIPtr[1]=newConnIPtr[0]+3;
5872 types.insert((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5873 newConn.insert(newConn.end(),conn+connI[i],conn+connI[i+1]);
5874 newConnIPtr[1]=newConnIPtr[0]+3;
5877 if(addCoo.empty() && ((int)newConn.size())==_nodal_connec->getNumberOfTuples())//nothing happens during tessellation : no update needed
5880 DataArrayInt::SetArrayIn(newConnI,_nodal_connec_index);
5881 MCAuto<DataArrayInt> newConnArr=DataArrayInt::New();
5882 newConnArr->alloc((int)newConn.size(),1);
5883 std::copy(newConn.begin(),newConn.end(),newConnArr->getPointer());
5884 DataArrayInt::SetArrayIn(newConnArr,_nodal_connec);
5885 MCAuto<DataArrayDouble> newCoords=DataArrayDouble::New();
5886 newCoords->alloc(nbNodes+((int)addCoo.size())/2,2);
5887 double *work=std::copy(_coords->begin(),_coords->end(),newCoords->getPointer());
5888 std::copy(addCoo.begin(),addCoo.end(),work);
5889 DataArrayDouble::SetArrayIn(newCoords,_coords);
5894 * This private method is used to subdivide edges of a mesh with meshdim==2. If \a this has no a meshdim equal to 2 an exception will be thrown.
5895 * This method completly ignore coordinates.
5896 * \param nodeSubdived is the nodal connectivity of subdivision of edges
5897 * \param nodeIndxSubdived is the nodal connectivity index of subdivision of edges
5898 * \param desc is descending connectivity in format specified in MEDCouplingUMesh::buildDescendingConnectivity2
5899 * \param descIndex is descending connectivity index in format specified in MEDCouplingUMesh::buildDescendingConnectivity2
5901 void MEDCouplingUMesh::subDivide2DMesh(const int *nodeSubdived, const int *nodeIndxSubdived, const int *desc, const int *descIndex)
5903 checkFullyDefined();
5904 if(getMeshDimension()!=2)
5905 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::subDivide2DMesh : works only on umesh with meshdim==2 !");
5906 int nbOfCells=getNumberOfCells();
5907 int *connI=_nodal_connec_index->getPointer();
5909 for(int i=0;i<nbOfCells;i++,connI++)
5911 int offset=descIndex[i];
5912 int nbOfEdges=descIndex[i+1]-offset;
5914 bool ddirect=desc[offset+nbOfEdges-1]>0;
5915 int eedgeId=std::abs(desc[offset+nbOfEdges-1])-1;
5916 int ref=ddirect?nodeSubdived[nodeIndxSubdived[eedgeId+1]-1]:nodeSubdived[nodeIndxSubdived[eedgeId]+1];
5917 for(int j=0;j<nbOfEdges;j++)
5919 bool direct=desc[offset+j]>0;
5920 int edgeId=std::abs(desc[offset+j])-1;
5921 if(!INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodeSubdived[nodeIndxSubdived[edgeId]]).isQuadratic())
5923 int id1=nodeSubdived[nodeIndxSubdived[edgeId]+1];
5924 int id2=nodeSubdived[nodeIndxSubdived[edgeId+1]-1];
5925 int ref2=direct?id1:id2;
5928 int nbOfSubNodes=nodeIndxSubdived[edgeId+1]-nodeIndxSubdived[edgeId]-1;
5929 newConnLgth+=nbOfSubNodes-1;
5934 std::ostringstream oss; oss << "MEDCouplingUMesh::subDivide2DMesh : On polygon #" << i << " edgeid #" << j << " subedges mismatch : end subedge k!=start subedge k+1 !";
5935 throw INTERP_KERNEL::Exception(oss.str().c_str());
5940 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::subDivide2DMesh : this method only subdivides into linear edges !");
5943 newConnLgth++;//+1 is for cell type
5944 connI[1]=newConnLgth;
5947 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5948 newConn->alloc(newConnLgth,1);
5949 int *work=newConn->getPointer();
5950 for(int i=0;i<nbOfCells;i++)
5952 *work++=INTERP_KERNEL::NORM_POLYGON;
5953 int offset=descIndex[i];
5954 int nbOfEdges=descIndex[i+1]-offset;
5955 for(int j=0;j<nbOfEdges;j++)
5957 bool direct=desc[offset+j]>0;
5958 int edgeId=std::abs(desc[offset+j])-1;
5960 work=std::copy(nodeSubdived+nodeIndxSubdived[edgeId]+1,nodeSubdived+nodeIndxSubdived[edgeId+1]-1,work);
5963 int nbOfSubNodes=nodeIndxSubdived[edgeId+1]-nodeIndxSubdived[edgeId]-1;
5964 std::reverse_iterator<const int *> it(nodeSubdived+nodeIndxSubdived[edgeId+1]);
5965 work=std::copy(it,it+nbOfSubNodes-1,work);
5969 DataArrayInt::SetArrayIn(newConn,_nodal_connec);
5972 _types.insert(INTERP_KERNEL::NORM_POLYGON);
5976 * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
5977 * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
5978 * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell. This method
5979 * does \b not perform geometrical checks and checks only nodal connectivity of cells,
5980 * so it can be useful to call mergeNodes() before calling this method.
5981 * \throw If \a this->getMeshDimension() <= 1.
5982 * \throw If the coordinates array is not set.
5983 * \throw If the nodal connectivity of cells is not defined.
5985 void MEDCouplingUMesh::convertDegeneratedCells()
5987 checkFullyDefined();
5988 if(getMeshDimension()<=1)
5989 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
5990 int nbOfCells=getNumberOfCells();
5993 int initMeshLgth=getNodalConnectivityArrayLen();
5994 int *conn=_nodal_connec->getPointer();
5995 int *index=_nodal_connec_index->getPointer();
5999 for(int i=0;i<nbOfCells;i++)
6001 lgthOfCurCell=index[i+1]-posOfCurCell;
6002 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
6004 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
6005 conn+newPos+1,newLgth);
6006 conn[newPos]=newType;
6008 posOfCurCell=index[i+1];
6011 if(newPos!=initMeshLgth)
6012 _nodal_connec->reAlloc(newPos);
6017 * Finds incorrectly oriented cells of this 2D mesh in 3D space.
6018 * A cell is considered to be oriented correctly if an angle between its
6019 * normal vector and a given vector is less than \c PI / \c 2.
6020 * \param [in] vec - 3 components of the vector specifying the correct orientation of
6022 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
6024 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
6025 * is not cleared before filling in.
6026 * \throw If \a this->getMeshDimension() != 2.
6027 * \throw If \a this->getSpaceDimension() != 3.
6029 * \if ENABLE_EXAMPLES
6030 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
6031 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
6034 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<int>& cells) const
6036 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6037 throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
6038 int nbOfCells=getNumberOfCells();
6039 const int *conn=_nodal_connec->getConstPointer();
6040 const int *connI=_nodal_connec_index->getConstPointer();
6041 const double *coordsPtr=_coords->getConstPointer();
6042 for(int i=0;i<nbOfCells;i++)
6044 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6045 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
6047 bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
6048 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6055 * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
6056 * considered to be oriented correctly if an angle between its normal vector and a
6057 * given vector is less than \c PI / \c 2.
6058 * \param [in] vec - 3 components of the vector specifying the correct orientation of
6060 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
6062 * \throw If \a this->getMeshDimension() != 2.
6063 * \throw If \a this->getSpaceDimension() != 3.
6065 * \if ENABLE_EXAMPLES
6066 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
6067 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
6070 * \sa changeOrientationOfCells
6072 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
6074 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6075 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
6076 int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
6077 const int *connI(_nodal_connec_index->getConstPointer());
6078 const double *coordsPtr(_coords->getConstPointer());
6079 bool isModified(false);
6080 for(int i=0;i<nbOfCells;i++)
6082 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6083 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
6085 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6086 bool isQuadratic(cm.isQuadratic());
6087 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6090 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6095 _nodal_connec->declareAsNew();
6100 * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
6102 * \sa orientCorrectly2DCells
6104 void MEDCouplingUMesh::changeOrientationOfCells()
6106 int mdim(getMeshDimension());
6107 if(mdim!=2 && mdim!=1)
6108 throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
6109 int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
6110 const int *connI(_nodal_connec_index->getConstPointer());
6113 for(int i=0;i<nbOfCells;i++)
6115 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6116 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6117 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6122 for(int i=0;i<nbOfCells;i++)
6124 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6125 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6126 cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6132 * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
6133 * oriented facets. The normal vector of the facet should point out of the cell.
6134 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
6135 * is not cleared before filling in.
6136 * \throw If \a this->getMeshDimension() != 3.
6137 * \throw If \a this->getSpaceDimension() != 3.
6138 * \throw If the coordinates array is not set.
6139 * \throw If the nodal connectivity of cells is not defined.
6141 * \if ENABLE_EXAMPLES
6142 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
6143 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
6146 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<int>& cells) const
6148 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6149 throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
6150 int nbOfCells=getNumberOfCells();
6151 const int *conn=_nodal_connec->getConstPointer();
6152 const int *connI=_nodal_connec_index->getConstPointer();
6153 const double *coordsPtr=_coords->getConstPointer();
6154 for(int i=0;i<nbOfCells;i++)
6156 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6157 if(type==INTERP_KERNEL::NORM_POLYHED)
6159 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6166 * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
6168 * \throw If \a this->getMeshDimension() != 3.
6169 * \throw If \a this->getSpaceDimension() != 3.
6170 * \throw If the coordinates array is not set.
6171 * \throw If the nodal connectivity of cells is not defined.
6172 * \throw If the reparation fails.
6174 * \if ENABLE_EXAMPLES
6175 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
6176 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
6178 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
6180 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
6182 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6183 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
6184 int nbOfCells=getNumberOfCells();
6185 int *conn=_nodal_connec->getPointer();
6186 const int *connI=_nodal_connec_index->getConstPointer();
6187 const double *coordsPtr=_coords->getConstPointer();
6188 for(int i=0;i<nbOfCells;i++)
6190 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6191 if(type==INTERP_KERNEL::NORM_POLYHED)
6195 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6196 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
6198 catch(INTERP_KERNEL::Exception& e)
6200 std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
6201 throw INTERP_KERNEL::Exception(oss.str().c_str());
6209 * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
6210 * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
6211 * according to which the first facet of the cell should be oriented to have the normal vector
6212 * pointing out of cell.
6213 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of fixed
6214 * cells. The caller is to delete this array using decrRef() as it is no more
6216 * \throw If \a this->getMeshDimension() != 3.
6217 * \throw If \a this->getSpaceDimension() != 3.
6218 * \throw If the coordinates array is not set.
6219 * \throw If the nodal connectivity of cells is not defined.
6221 * \if ENABLE_EXAMPLES
6222 * \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
6223 * \ref py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
6225 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
6227 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
6229 const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
6230 if(getMeshDimension()!=3)
6231 throw INTERP_KERNEL::Exception(msg);
6232 int spaceDim=getSpaceDimension();
6234 throw INTERP_KERNEL::Exception(msg);
6236 int nbOfCells=getNumberOfCells();
6237 int *conn=_nodal_connec->getPointer();
6238 const int *connI=_nodal_connec_index->getConstPointer();
6239 const double *coo=getCoords()->getConstPointer();
6240 MCAuto<DataArrayInt> cells(DataArrayInt::New()); cells->alloc(0,1);
6241 for(int i=0;i<nbOfCells;i++)
6243 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6244 if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
6246 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
6248 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
6249 cells->pushBackSilent(i);
6253 return cells.retn();
6257 * This method is a faster method to correct orientation of all 3D cells in \a this.
6258 * 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.
6259 * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
6261 * \return a newly allocated int array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
6262 * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
6264 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
6266 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6267 throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
6268 int nbOfCells=getNumberOfCells();
6269 int *conn=_nodal_connec->getPointer();
6270 const int *connI=_nodal_connec_index->getConstPointer();
6271 const double *coordsPtr=_coords->getConstPointer();
6272 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
6273 for(int i=0;i<nbOfCells;i++)
6275 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6278 case INTERP_KERNEL::NORM_TETRA4:
6280 if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6282 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
6283 ret->pushBackSilent(i);
6287 case INTERP_KERNEL::NORM_PYRA5:
6289 if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6291 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
6292 ret->pushBackSilent(i);
6296 case INTERP_KERNEL::NORM_PENTA6:
6297 case INTERP_KERNEL::NORM_HEXA8:
6298 case INTERP_KERNEL::NORM_HEXGP12:
6300 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6302 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
6303 ret->pushBackSilent(i);
6307 case INTERP_KERNEL::NORM_POLYHED:
6309 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6311 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
6312 ret->pushBackSilent(i);
6317 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 !");
6325 * This method has a sense for meshes with spaceDim==3 and meshDim==2.
6326 * If it is not the case an exception will be thrown.
6327 * This method is fast because the first cell of \a this is used to compute the plane.
6328 * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
6329 * \param pos output of size at least 3 used to store a point owned of searched plane.
6331 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
6333 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6334 throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
6335 const int *conn=_nodal_connec->getConstPointer();
6336 const int *connI=_nodal_connec_index->getConstPointer();
6337 const double *coordsPtr=_coords->getConstPointer();
6338 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
6339 std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
6343 * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
6344 * cells. Currently cells of the following types are treated:
6345 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
6346 * For a cell of other type an exception is thrown.
6347 * Space dimension of a 2D mesh can be either 2 or 3.
6348 * The Edge Ratio of a cell \f$t\f$ is:
6349 * \f$\frac{|t|_\infty}{|t|_0}\f$,
6350 * where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
6351 * the smallest edge lengths of \f$t\f$.
6352 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6353 * cells and one time, lying on \a this mesh. The caller is to delete this
6354 * field using decrRef() as it is no more needed.
6355 * \throw If the coordinates array is not set.
6356 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6357 * \throw If the connectivity data array has more than one component.
6358 * \throw If the connectivity data array has a named component.
6359 * \throw If the connectivity index data array has more than one component.
6360 * \throw If the connectivity index data array has a named component.
6361 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
6362 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
6363 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
6365 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
6367 checkConsistencyLight();
6368 int spaceDim=getSpaceDimension();
6369 int meshDim=getMeshDimension();
6370 if(spaceDim!=2 && spaceDim!=3)
6371 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
6372 if(meshDim!=2 && meshDim!=3)
6373 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
6374 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6376 int nbOfCells=getNumberOfCells();
6377 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6378 arr->alloc(nbOfCells,1);
6379 double *pt=arr->getPointer();
6380 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6381 const int *conn=_nodal_connec->getConstPointer();
6382 const int *connI=_nodal_connec_index->getConstPointer();
6383 const double *coo=_coords->getConstPointer();
6385 for(int i=0;i<nbOfCells;i++,pt++)
6387 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6390 case INTERP_KERNEL::NORM_TRI3:
6392 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
6393 *pt=INTERP_KERNEL::triEdgeRatio(tmp);
6396 case INTERP_KERNEL::NORM_QUAD4:
6398 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6399 *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
6402 case INTERP_KERNEL::NORM_TETRA4:
6404 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6405 *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
6409 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
6411 conn+=connI[i+1]-connI[i];
6413 ret->setName("EdgeRatio");
6414 ret->synchronizeTimeWithSupport();
6419 * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
6420 * cells. Currently cells of the following types are treated:
6421 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
6422 * For a cell of other type an exception is thrown.
6423 * Space dimension of a 2D mesh can be either 2 or 3.
6424 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6425 * cells and one time, lying on \a this mesh. The caller is to delete this
6426 * field using decrRef() as it is no more needed.
6427 * \throw If the coordinates array is not set.
6428 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6429 * \throw If the connectivity data array has more than one component.
6430 * \throw If the connectivity data array has a named component.
6431 * \throw If the connectivity index data array has more than one component.
6432 * \throw If the connectivity index data array has a named component.
6433 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
6434 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
6435 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
6437 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
6439 checkConsistencyLight();
6440 int spaceDim=getSpaceDimension();
6441 int meshDim=getMeshDimension();
6442 if(spaceDim!=2 && spaceDim!=3)
6443 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
6444 if(meshDim!=2 && meshDim!=3)
6445 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
6446 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6448 int nbOfCells=getNumberOfCells();
6449 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6450 arr->alloc(nbOfCells,1);
6451 double *pt=arr->getPointer();
6452 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6453 const int *conn=_nodal_connec->getConstPointer();
6454 const int *connI=_nodal_connec_index->getConstPointer();
6455 const double *coo=_coords->getConstPointer();
6457 for(int i=0;i<nbOfCells;i++,pt++)
6459 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6462 case INTERP_KERNEL::NORM_TRI3:
6464 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
6465 *pt=INTERP_KERNEL::triAspectRatio(tmp);
6468 case INTERP_KERNEL::NORM_QUAD4:
6470 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6471 *pt=INTERP_KERNEL::quadAspectRatio(tmp);
6474 case INTERP_KERNEL::NORM_TETRA4:
6476 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6477 *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
6481 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
6483 conn+=connI[i+1]-connI[i];
6485 ret->setName("AspectRatio");
6486 ret->synchronizeTimeWithSupport();
6491 * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
6492 * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
6493 * in 3D space. Currently only cells of the following types are
6494 * treated: INTERP_KERNEL::NORM_QUAD4.
6495 * For a cell of other type an exception is thrown.
6496 * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
6498 * \f$t=\vec{da}\times\vec{ab}\f$,
6499 * \f$u=\vec{ab}\times\vec{bc}\f$
6500 * \f$v=\vec{bc}\times\vec{cd}\f$
6501 * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
6503 * W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
6505 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6506 * cells and one time, lying on \a this mesh. The caller is to delete this
6507 * field using decrRef() as it is no more needed.
6508 * \throw If the coordinates array is not set.
6509 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6510 * \throw If the connectivity data array has more than one component.
6511 * \throw If the connectivity data array has a named component.
6512 * \throw If the connectivity index data array has more than one component.
6513 * \throw If the connectivity index data array has a named component.
6514 * \throw If \a this->getMeshDimension() != 2.
6515 * \throw If \a this->getSpaceDimension() != 3.
6516 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
6518 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
6520 checkConsistencyLight();
6521 int spaceDim=getSpaceDimension();
6522 int meshDim=getMeshDimension();
6524 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
6526 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
6527 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6529 int nbOfCells=getNumberOfCells();
6530 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6531 arr->alloc(nbOfCells,1);
6532 double *pt=arr->getPointer();
6533 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6534 const int *conn=_nodal_connec->getConstPointer();
6535 const int *connI=_nodal_connec_index->getConstPointer();
6536 const double *coo=_coords->getConstPointer();
6538 for(int i=0;i<nbOfCells;i++,pt++)
6540 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6543 case INTERP_KERNEL::NORM_QUAD4:
6545 FillInCompact3DMode(3,4,conn+1,coo,tmp);
6546 *pt=INTERP_KERNEL::quadWarp(tmp);
6550 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
6552 conn+=connI[i+1]-connI[i];
6554 ret->setName("Warp");
6555 ret->synchronizeTimeWithSupport();
6561 * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
6562 * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
6563 * treated: INTERP_KERNEL::NORM_QUAD4.
6564 * The skew is computed as follow for a quad with points (a,b,c,d): let
6565 * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
6566 * then the skew is computed as:
6568 * s=\frac{u}{|u|}\cdot\frac{v}{|v|}
6571 * For a cell of other type an exception is thrown.
6572 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6573 * cells and one time, lying on \a this mesh. The caller is to delete this
6574 * field using decrRef() as it is no more needed.
6575 * \throw If the coordinates array is not set.
6576 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6577 * \throw If the connectivity data array has more than one component.
6578 * \throw If the connectivity data array has a named component.
6579 * \throw If the connectivity index data array has more than one component.
6580 * \throw If the connectivity index data array has a named component.
6581 * \throw If \a this->getMeshDimension() != 2.
6582 * \throw If \a this->getSpaceDimension() != 3.
6583 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
6585 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
6587 checkConsistencyLight();
6588 int spaceDim=getSpaceDimension();
6589 int meshDim=getMeshDimension();
6591 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
6593 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
6594 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6596 int nbOfCells=getNumberOfCells();
6597 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6598 arr->alloc(nbOfCells,1);
6599 double *pt=arr->getPointer();
6600 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6601 const int *conn=_nodal_connec->getConstPointer();
6602 const int *connI=_nodal_connec_index->getConstPointer();
6603 const double *coo=_coords->getConstPointer();
6605 for(int i=0;i<nbOfCells;i++,pt++)
6607 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6610 case INTERP_KERNEL::NORM_QUAD4:
6612 FillInCompact3DMode(3,4,conn+1,coo,tmp);
6613 *pt=INTERP_KERNEL::quadSkew(tmp);
6617 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
6619 conn+=connI[i+1]-connI[i];
6621 ret->setName("Skew");
6622 ret->synchronizeTimeWithSupport();
6627 * 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.
6629 * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
6631 * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
6633 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
6635 checkConsistencyLight();
6636 MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
6638 std::set<INTERP_KERNEL::NormalizedCellType> types;
6639 ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
6640 int spaceDim(getSpaceDimension()),nbCells(getNumberOfCells());
6641 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6642 arr->alloc(nbCells,1);
6643 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
6645 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
6646 MCAuto<DataArrayInt> cellIds(giveCellsWithType(*it));
6647 dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
6650 ret->setName("Diameter");
6655 * This method aggregate the bbox of each cell and put it into bbox parameter.
6657 * \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)
6658 * For all other cases this input parameter is ignored.
6659 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6661 * \throw If \a this is not fully set (coordinates and connectivity).
6662 * \throw If a cell in \a this has no valid nodeId.
6663 * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
6665 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
6667 int mDim(getMeshDimension()),sDim(getSpaceDimension());
6668 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.
6669 return getBoundingBoxForBBTreeFast();
6670 if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
6672 bool presenceOfQuadratic(false);
6673 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
6675 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
6676 if(cm.isQuadratic())
6677 presenceOfQuadratic=true;
6679 if(!presenceOfQuadratic)
6680 return getBoundingBoxForBBTreeFast();
6681 if(mDim==2 && sDim==2)
6682 return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
6684 return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
6686 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) !");
6690 * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
6691 * So meshes having quadratic cells the computed bounding boxes can be invalid !
6693 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6695 * \throw If \a this is not fully set (coordinates and connectivity).
6696 * \throw If a cell in \a this has no valid nodeId.
6698 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
6700 checkFullyDefined();
6701 int spaceDim(getSpaceDimension()),nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
6702 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6703 double *bbox(ret->getPointer());
6704 for(int i=0;i<nbOfCells*spaceDim;i++)
6706 bbox[2*i]=std::numeric_limits<double>::max();
6707 bbox[2*i+1]=-std::numeric_limits<double>::max();
6709 const double *coordsPtr(_coords->getConstPointer());
6710 const int *conn(_nodal_connec->getConstPointer()),*connI(_nodal_connec_index->getConstPointer());
6711 for(int i=0;i<nbOfCells;i++)
6713 int offset=connI[i]+1;
6714 int nbOfNodesForCell(connI[i+1]-offset),kk(0);
6715 for(int j=0;j<nbOfNodesForCell;j++)
6717 int nodeId=conn[offset+j];
6718 if(nodeId>=0 && nodeId<nbOfNodes)
6720 for(int k=0;k<spaceDim;k++)
6722 bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
6723 bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
6730 std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
6731 throw INTERP_KERNEL::Exception(oss.str().c_str());
6738 * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
6739 * useful for 2D meshes having quadratic cells
6740 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
6741 * the two extremities of the arc of circle).
6743 * \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)
6744 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6745 * \throw If \a this is not fully defined.
6746 * \throw If \a this is not a mesh with meshDimension equal to 2.
6747 * \throw If \a this is not a mesh with spaceDimension equal to 2.
6748 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
6750 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
6752 checkFullyDefined();
6753 int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
6754 if(spaceDim!=2 || mDim!=2)
6755 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!");
6756 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6757 double *bbox(ret->getPointer());
6758 const double *coords(_coords->getConstPointer());
6759 const int *conn(_nodal_connec->getConstPointer()),*connI(_nodal_connec_index->getConstPointer());
6760 for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
6762 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
6763 int sz(connI[1]-connI[0]-1);
6764 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=arcDetEps;
6765 std::vector<INTERP_KERNEL::Node *> nodes(sz);
6766 INTERP_KERNEL::QuadraticPolygon *pol(0);
6767 for(int j=0;j<sz;j++)
6769 int nodeId(conn[*connI+1+j]);
6770 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
6772 if(!cm.isQuadratic())
6773 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
6775 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
6776 INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
6777 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
6783 * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
6784 * useful for 2D meshes having quadratic cells
6785 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
6786 * the two extremities of the arc of circle).
6788 * \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)
6789 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6790 * \throw If \a this is not fully defined.
6791 * \throw If \a this is not a mesh with meshDimension equal to 1.
6792 * \throw If \a this is not a mesh with spaceDimension equal to 2.
6793 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
6795 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
6797 checkFullyDefined();
6798 int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
6799 if(spaceDim!=2 || mDim!=1)
6800 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!");
6801 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6802 double *bbox(ret->getPointer());
6803 const double *coords(_coords->getConstPointer());
6804 const int *conn(_nodal_connec->getConstPointer()),*connI(_nodal_connec_index->getConstPointer());
6805 for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
6807 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
6808 int sz(connI[1]-connI[0]-1);
6809 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=arcDetEps;
6810 std::vector<INTERP_KERNEL::Node *> nodes(sz);
6811 INTERP_KERNEL::Edge *edge(0);
6812 for(int j=0;j<sz;j++)
6814 int nodeId(conn[*connI+1+j]);
6815 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
6817 if(!cm.isQuadratic())
6818 edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
6820 edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
6821 const INTERP_KERNEL::Bounds& b(edge->getBounds());
6822 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
6829 namespace MEDCouplingImpl
6834 ConnReader(const int *c, int val):_conn(c),_val(val) { }
6835 bool operator() (const int& pos) { return _conn[pos]!=_val; }
6844 ConnReader2(const int *c, int val):_conn(c),_val(val) { }
6845 bool operator() (const int& pos) { return _conn[pos]==_val; }
6855 * This method expects that \a this is sorted by types. If not an exception will be thrown.
6856 * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
6857 * \a this is composed in cell types.
6858 * The returned array is of size 3*n where n is the number of different types present in \a this.
6859 * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
6860 * This parameter is kept only for compatibility with other methode listed above.
6862 std::vector<int> MEDCouplingUMesh::getDistributionOfTypes() const
6864 checkConnectivityFullyDefined();
6865 const int *conn=_nodal_connec->getConstPointer();
6866 const int *connI=_nodal_connec_index->getConstPointer();
6867 const int *work=connI;
6868 int nbOfCells=getNumberOfCells();
6869 std::size_t n=getAllGeoTypes().size();
6870 std::vector<int> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
6871 std::set<INTERP_KERNEL::NormalizedCellType> types;
6872 for(std::size_t i=0;work!=connI+nbOfCells;i++)
6874 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
6875 if(types.find(typ)!=types.end())
6877 std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
6878 oss << " is not contiguous !";
6879 throw INTERP_KERNEL::Exception(oss.str().c_str());
6883 const int *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
6884 ret[3*i+1]=(int)std::distance(work,work2);
6891 * This method is used to check that this has contiguous cell type in same order than described in \a code.
6892 * only for types cell, type node is not managed.
6893 * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
6894 * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
6895 * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
6896 * If 2 or more same geometric type is in \a code and exception is thrown too.
6898 * This method firstly checks
6899 * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
6900 * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
6901 * an exception is thrown too.
6903 * If all geometric types in \a code are exactly those in \a this null pointer is returned.
6904 * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
6905 * and a DataArrayInt instance is returned that the user has the responsability to deallocate.
6907 DataArrayInt *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<int>& code, const std::vector<const DataArrayInt *>& idsPerType) const
6910 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
6911 std::size_t sz=code.size();
6914 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
6915 std::vector<INTERP_KERNEL::NormalizedCellType> types;
6917 bool isNoPflUsed=true;
6918 for(std::size_t i=0;i<n;i++)
6919 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
6921 types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
6923 if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
6924 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
6925 isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
6928 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
6931 if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
6932 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
6933 if(types.size()==_types.size())
6936 MCAuto<DataArrayInt> ret=DataArrayInt::New();
6938 int *retPtr=ret->getPointer();
6939 const int *connI=_nodal_connec_index->getConstPointer();
6940 const int *conn=_nodal_connec->getConstPointer();
6941 int nbOfCells=getNumberOfCells();
6944 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
6946 i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,(int)(*it)));
6947 int offset=(int)std::distance(connI,i);
6948 const int *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)(*it)));
6949 int nbOfCellsOfCurType=(int)std::distance(i,j);
6950 if(code[3*kk+2]==-1)
6951 for(int k=0;k<nbOfCellsOfCurType;k++)
6955 int idInIdsPerType=code[3*kk+2];
6956 if(idInIdsPerType>=0 && idInIdsPerType<(int)idsPerType.size())
6958 const DataArrayInt *zePfl=idsPerType[idInIdsPerType];
6961 zePfl->checkAllocated();
6962 if(zePfl->getNumberOfComponents()==1)
6964 for(const int *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
6966 if(*k>=0 && *k<nbOfCellsOfCurType)
6967 *retPtr=(*k)+offset;
6970 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
6971 oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
6972 throw INTERP_KERNEL::Exception(oss.str().c_str());
6977 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
6980 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
6984 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
6985 oss << " should be in [0," << idsPerType.size() << ") !";
6986 throw INTERP_KERNEL::Exception(oss.str().c_str());
6995 * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
6996 * 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.
6997 * 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.
6998 * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
7000 * \param [in] profile
7001 * \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.
7002 * \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,
7003 * \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
7004 * \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.
7005 * This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
7006 * \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
7008 void MEDCouplingUMesh::splitProfilePerType(const DataArrayInt *profile, std::vector<int>& code, std::vector<DataArrayInt *>& idsInPflPerType, std::vector<DataArrayInt *>& idsPerType) const
7011 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
7012 if(profile->getNumberOfComponents()!=1)
7013 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
7014 checkConnectivityFullyDefined();
7015 const int *conn=_nodal_connec->getConstPointer();
7016 const int *connI=_nodal_connec_index->getConstPointer();
7017 int nbOfCells=getNumberOfCells();
7018 std::vector<INTERP_KERNEL::NormalizedCellType> types;
7019 std::vector<int> typeRangeVals(1);
7020 for(const int *i=connI;i!=connI+nbOfCells;)
7022 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7023 if(std::find(types.begin(),types.end(),curType)!=types.end())
7025 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
7027 types.push_back(curType);
7028 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7029 typeRangeVals.push_back((int)std::distance(connI,i));
7032 DataArrayInt *castArr=0,*rankInsideCast=0,*castsPresent=0;
7033 profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
7034 MCAuto<DataArrayInt> tmp0=castArr;
7035 MCAuto<DataArrayInt> tmp1=rankInsideCast;
7036 MCAuto<DataArrayInt> tmp2=castsPresent;
7038 int nbOfCastsFinal=castsPresent->getNumberOfTuples();
7039 code.resize(3*nbOfCastsFinal);
7040 std::vector< MCAuto<DataArrayInt> > idsInPflPerType2;
7041 std::vector< MCAuto<DataArrayInt> > idsPerType2;
7042 for(int i=0;i<nbOfCastsFinal;i++)
7044 int castId=castsPresent->getIJ(i,0);
7045 MCAuto<DataArrayInt> tmp3=castArr->findIdsEqual(castId);
7046 idsInPflPerType2.push_back(tmp3);
7047 code[3*i]=(int)types[castId];
7048 code[3*i+1]=tmp3->getNumberOfTuples();
7049 MCAuto<DataArrayInt> tmp4=rankInsideCast->selectByTupleId(tmp3->getConstPointer(),tmp3->getConstPointer()+tmp3->getNumberOfTuples());
7050 if(!tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
7052 tmp4->copyStringInfoFrom(*profile);
7053 idsPerType2.push_back(tmp4);
7054 code[3*i+2]=(int)idsPerType2.size()-1;
7061 std::size_t sz2=idsInPflPerType2.size();
7062 idsInPflPerType.resize(sz2);
7063 for(std::size_t i=0;i<sz2;i++)
7065 DataArrayInt *locDa=idsInPflPerType2[i];
7067 idsInPflPerType[i]=locDa;
7069 std::size_t sz=idsPerType2.size();
7070 idsPerType.resize(sz);
7071 for(std::size_t i=0;i<sz;i++)
7073 DataArrayInt *locDa=idsPerType2[i];
7075 idsPerType[i]=locDa;
7080 * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
7081 * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
7082 * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
7083 * 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.
7085 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *&revDesc, DataArrayInt *&revDescIndx, DataArrayInt *& nM1LevMeshIds, DataArrayInt *&meshnM1Old2New) const
7087 checkFullyDefined();
7088 nM1LevMesh->checkFullyDefined();
7089 if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
7090 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
7091 if(_coords!=nM1LevMesh->getCoords())
7092 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
7093 MCAuto<DataArrayInt> tmp0=DataArrayInt::New();
7094 MCAuto<DataArrayInt> tmp1=DataArrayInt::New();
7095 MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
7096 MCAuto<DataArrayInt> ret0=ret1->sortCellsInMEDFileFrmt();
7097 desc->transformWithIndArr(ret0->getConstPointer(),ret0->getConstPointer()+ret0->getNbOfElems());
7098 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
7099 tmp->setConnectivity(tmp0,tmp1);
7100 tmp->renumberCells(ret0->getConstPointer(),false);
7101 revDesc=tmp->getNodalConnectivity();
7102 revDescIndx=tmp->getNodalConnectivityIndex();
7103 DataArrayInt *ret=0;
7104 if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
7107 ret->getMaxValue(tmp2);
7109 std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
7110 throw INTERP_KERNEL::Exception(oss.str().c_str());
7115 revDescIndx->incrRef();
7118 meshnM1Old2New=ret0;
7123 * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
7124 * necessary for writing the mesh to MED file. Additionally returns a permutation array
7125 * in "Old to New" mode.
7126 * \return DataArrayInt * - a new instance of DataArrayInt. The caller is to delete
7127 * this array using decrRef() as it is no more needed.
7128 * \throw If the nodal connectivity of cells is not defined.
7130 DataArrayInt *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
7132 checkConnectivityFullyDefined();
7133 MCAuto<DataArrayInt> ret=getRenumArrForMEDFileFrmt();
7134 renumberCells(ret->getConstPointer(),false);
7139 * This methods checks that cells are sorted by their types.
7140 * This method makes asumption (no check) that connectivity is correctly set before calling.
7142 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
7144 checkFullyDefined();
7145 const int *conn=_nodal_connec->getConstPointer();
7146 const int *connI=_nodal_connec_index->getConstPointer();
7147 int nbOfCells=getNumberOfCells();
7148 std::set<INTERP_KERNEL::NormalizedCellType> types;
7149 for(const int *i=connI;i!=connI+nbOfCells;)
7151 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7152 if(types.find(curType)!=types.end())
7154 types.insert(curType);
7155 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7161 * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
7162 * The geometric type order is specified by MED file.
7164 * \sa MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
7166 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
7168 return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
7172 * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
7173 * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
7174 * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
7175 * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
7177 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
7179 checkFullyDefined();
7180 const int *conn=_nodal_connec->getConstPointer();
7181 const int *connI=_nodal_connec_index->getConstPointer();
7182 int nbOfCells=getNumberOfCells();
7186 std::set<INTERP_KERNEL::NormalizedCellType> sg;
7187 for(const int *i=connI;i!=connI+nbOfCells;)
7189 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7190 const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
7191 if(isTypeExists!=orderEnd)
7193 int pos=(int)std::distance(orderBg,isTypeExists);
7197 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7201 if(sg.find(curType)==sg.end())
7203 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7214 * This method returns 2 newly allocated DataArrayInt instances. The first is an array of size 'this->getNumberOfCells()' with one component,
7215 * 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
7216 * number of tuples than input type array and with one component. This 2nd output array gives type by type the number of occurence of type in 'this'.
7218 DataArrayInt *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayInt *&nbPerType) const
7220 checkConnectivityFullyDefined();
7221 int nbOfCells=getNumberOfCells();
7222 const int *conn=_nodal_connec->getConstPointer();
7223 const int *connI=_nodal_connec_index->getConstPointer();
7224 MCAuto<DataArrayInt> tmpa=DataArrayInt::New();
7225 MCAuto<DataArrayInt> tmpb=DataArrayInt::New();
7226 tmpa->alloc(nbOfCells,1);
7227 tmpb->alloc((int)std::distance(orderBg,orderEnd),1);
7228 tmpb->fillWithZero();
7229 int *tmp=tmpa->getPointer();
7230 int *tmp2=tmpb->getPointer();
7231 for(const int *i=connI;i!=connI+nbOfCells;i++)
7233 const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
7236 int pos=(int)std::distance(orderBg,where);
7238 tmp[std::distance(connI,i)]=pos;
7242 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
7243 std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
7244 oss << " has a type " << cm.getRepr() << " not in input array of type !";
7245 throw INTERP_KERNEL::Exception(oss.str().c_str());
7248 nbPerType=tmpb.retn();
7253 * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
7255 * \return a new object containing the old to new correspondance.
7257 * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
7259 DataArrayInt *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
7261 return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
7265 * This method is similar to method MEDCouplingUMesh::rearrange2ConsecutiveCellTypes except that the type order is specfied by [ \a orderBg , \a orderEnd ) (as MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method) and that this method is \b const and performs \b NO permutation in \a this.
7266 * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
7267 * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
7268 * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
7270 DataArrayInt *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
7272 DataArrayInt *nbPerType=0;
7273 MCAuto<DataArrayInt> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
7274 nbPerType->decrRef();
7275 return tmpa->buildPermArrPerLevel();
7279 * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
7280 * The number of cells remains unchanged after the call of this method.
7281 * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
7282 * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
7284 * \return the array giving the correspondance old to new.
7286 DataArrayInt *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
7288 checkFullyDefined();
7290 const int *conn=_nodal_connec->getConstPointer();
7291 const int *connI=_nodal_connec_index->getConstPointer();
7292 int nbOfCells=getNumberOfCells();
7293 std::vector<INTERP_KERNEL::NormalizedCellType> types;
7294 for(const int *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
7295 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
7297 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7298 types.push_back(curType);
7299 for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
7301 DataArrayInt *ret=DataArrayInt::New();
7302 ret->alloc(nbOfCells,1);
7303 int *retPtr=ret->getPointer();
7304 std::fill(retPtr,retPtr+nbOfCells,-1);
7306 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
7308 for(const int *i=connI;i!=connI+nbOfCells;i++)
7309 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
7310 retPtr[std::distance(connI,i)]=newCellId++;
7312 renumberCells(retPtr,false);
7317 * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
7318 * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
7319 * This method makes asumption that connectivity is correctly set before calling.
7321 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
7323 checkConnectivityFullyDefined();
7324 const int *conn=_nodal_connec->getConstPointer();
7325 const int *connI=_nodal_connec_index->getConstPointer();
7326 int nbOfCells=getNumberOfCells();
7327 std::vector<MEDCouplingUMesh *> ret;
7328 for(const int *i=connI;i!=connI+nbOfCells;)
7330 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7331 int beginCellId=(int)std::distance(connI,i);
7332 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7333 int endCellId=(int)std::distance(connI,i);
7334 int sz=endCellId-beginCellId;
7335 int *cells=new int[sz];
7336 for(int j=0;j<sz;j++)
7337 cells[j]=beginCellId+j;
7338 MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
7346 * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
7347 * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
7348 * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
7350 * \return a newly allocated instance, that the caller must manage.
7351 * \throw If \a this contains more than one geometric type.
7352 * \throw If the nodal connectivity of \a this is not fully defined.
7353 * \throw If the internal data is not coherent.
7355 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
7357 checkConnectivityFullyDefined();
7358 if(_types.size()!=1)
7359 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7360 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
7361 MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
7362 ret->setCoords(getCoords());
7363 MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
7366 MCAuto<DataArrayInt> c=convertNodalConnectivityToStaticGeoTypeMesh();
7367 retC->setNodalConnectivity(c);
7371 MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
7373 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
7374 DataArrayInt *c=0,*ci=0;
7375 convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
7376 MCAuto<DataArrayInt> cs(c),cis(ci);
7377 retD->setNodalConnectivity(cs,cis);
7382 DataArrayInt *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
7384 checkConnectivityFullyDefined();
7385 if(_types.size()!=1)
7386 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7387 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
7388 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
7391 std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
7392 oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
7393 throw INTERP_KERNEL::Exception(oss.str().c_str());
7395 int nbCells=getNumberOfCells();
7397 int nbNodesPerCell=(int)cm.getNumberOfNodes();
7398 MCAuto<DataArrayInt> connOut=DataArrayInt::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
7399 int *outPtr=connOut->getPointer();
7400 const int *conn=_nodal_connec->begin();
7401 const int *connI=_nodal_connec_index->begin();
7403 for(int i=0;i<nbCells;i++,connI++)
7405 if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
7406 outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
7409 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 << ") !";
7410 throw INTERP_KERNEL::Exception(oss.str().c_str());
7413 return connOut.retn();
7417 * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
7418 * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
7422 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayInt *&nodalConn, DataArrayInt *&nodalConnIndex) const
7424 static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
7425 checkConnectivityFullyDefined();
7426 if(_types.size()!=1)
7427 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7428 int nbCells=getNumberOfCells(),lgth=_nodal_connec->getNumberOfTuples();
7430 throw INTERP_KERNEL::Exception(msg0);
7431 MCAuto<DataArrayInt> c(DataArrayInt::New()),ci(DataArrayInt::New());
7432 c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
7433 int *cp(c->getPointer()),*cip(ci->getPointer());
7434 const int *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
7436 for(int i=0;i<nbCells;i++,cip++,incip++)
7438 int strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
7439 int delta(stop-strt);
7442 if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
7443 cp=std::copy(incp+strt,incp+stop,cp);
7445 throw INTERP_KERNEL::Exception(msg0);
7448 throw INTERP_KERNEL::Exception(msg0);
7449 cip[1]=cip[0]+delta;
7451 nodalConn=c.retn(); nodalConnIndex=ci.retn();
7455 * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
7456 * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
7457 * This method is particulary useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
7458 * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
7459 * are not used here to avoid the build of big permutation array.
7461 * \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
7462 * those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
7463 * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayInt instance whose number of tuples is equal to the number of chunks of same geotype
7464 * in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
7465 * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayInt instance having the same size than \b szOfCellGrpOfSameType. This
7466 * output array gives for each chunck of same type the corresponding mesh id in \b ms.
7467 * \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
7468 * is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
7470 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
7471 DataArrayInt *&szOfCellGrpOfSameType,
7472 DataArrayInt *&idInMsOfCellGrpOfSameType)
7474 std::vector<const MEDCouplingUMesh *> ms2;
7475 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
7478 (*it)->checkConnectivityFullyDefined();
7482 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
7483 const DataArrayDouble *refCoo=ms2[0]->getCoords();
7484 int meshDim=ms2[0]->getMeshDimension();
7485 std::vector<const MEDCouplingUMesh *> m1ssm;
7486 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
7488 std::vector<const MEDCouplingUMesh *> m1ssmSingle;
7489 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
7491 MCAuto<DataArrayInt> ret1(DataArrayInt::New()),ret2(DataArrayInt::New());
7492 ret1->alloc(0,1); ret2->alloc(0,1);
7493 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
7495 if(meshDim!=(*it)->getMeshDimension())
7496 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
7497 if(refCoo!=(*it)->getCoords())
7498 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
7499 std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
7500 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
7501 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
7502 for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
7504 MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
7505 m1ssmSingleAuto.push_back(singleCell);
7506 m1ssmSingle.push_back(singleCell);
7507 ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
7510 MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
7511 MCAuto<DataArrayInt> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
7512 std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
7513 for(std::size_t i=0;i<m1ssm.size();i++)
7514 m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
7515 MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
7516 szOfCellGrpOfSameType=ret1->renumber(renum->getConstPointer());
7517 idInMsOfCellGrpOfSameType=ret2->renumber(renum->getConstPointer());
7522 * This method returns a newly created DataArrayInt instance.
7523 * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
7525 DataArrayInt *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const int *begin, const int *end) const
7527 checkFullyDefined();
7528 const int *conn=_nodal_connec->getConstPointer();
7529 const int *connIndex=_nodal_connec_index->getConstPointer();
7530 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
7531 for(const int *w=begin;w!=end;w++)
7532 if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
7533 ret->pushBackSilent(*w);
7538 * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
7539 * are in [0:getNumberOfCells())
7541 DataArrayInt *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayInt *da) const
7543 checkFullyDefined();
7544 const int *conn=_nodal_connec->getConstPointer();
7545 const int *connI=_nodal_connec_index->getConstPointer();
7546 int nbOfCells=getNumberOfCells();
7547 std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
7548 int *tmp=new int[nbOfCells];
7549 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
7552 for(const int *i=connI;i!=connI+nbOfCells;i++)
7553 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
7554 tmp[std::distance(connI,i)]=j++;
7556 DataArrayInt *ret=DataArrayInt::New();
7557 ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
7558 ret->copyStringInfoFrom(*da);
7559 int *retPtr=ret->getPointer();
7560 const int *daPtr=da->getConstPointer();
7561 int nbOfElems=da->getNbOfElems();
7562 for(int k=0;k<nbOfElems;k++)
7563 retPtr[k]=tmp[daPtr[k]];
7569 * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
7570 * This method \b works \b for mesh sorted by type.
7571 * cells whose ids is in 'idsPerGeoType' array.
7572 * This method conserves coords and name of mesh.
7574 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const int *idsPerGeoTypeBg, const int *idsPerGeoTypeEnd) const
7576 std::vector<int> code=getDistributionOfTypes();
7577 std::size_t nOfTypesInThis=code.size()/3;
7578 int sz=0,szOfType=0;
7579 for(std::size_t i=0;i<nOfTypesInThis;i++)
7584 szOfType=code[3*i+1];
7586 for(const int *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
7587 if(*work<0 || *work>=szOfType)
7589 std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
7590 oss << ". It should be in [0," << szOfType << ") !";
7591 throw INTERP_KERNEL::Exception(oss.str().c_str());
7593 MCAuto<DataArrayInt> idsTokeep=DataArrayInt::New(); idsTokeep->alloc(sz+(int)std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
7594 int *idsPtr=idsTokeep->getPointer();
7596 for(std::size_t i=0;i<nOfTypesInThis;i++)
7599 for(int j=0;j<code[3*i+1];j++)
7602 idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind2nd(std::plus<int>(),offset));
7603 offset+=code[3*i+1];
7605 MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
7606 ret->copyTinyInfoFrom(this);
7611 * This method returns a vector of size 'this->getNumberOfCells()'.
7612 * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
7614 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
7616 int ncell=getNumberOfCells();
7617 std::vector<bool> ret(ncell);
7618 const int *cI=getNodalConnectivityIndex()->getConstPointer();
7619 const int *c=getNodalConnectivity()->getConstPointer();
7620 for(int i=0;i<ncell;i++)
7622 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
7623 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
7624 ret[i]=cm.isQuadratic();
7630 * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
7632 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
7634 if(other->getType()!=UNSTRUCTURED)
7635 throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
7636 const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
7637 return MergeUMeshes(this,otherC);
7641 * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
7642 * computed by averaging coordinates of cell nodes, so this method is not a right
7643 * choice for degnerated meshes (not well oriented, cells with measure close to zero).
7644 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
7645 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
7646 * components. The caller is to delete this array using decrRef() as it is
7648 * \throw If the coordinates array is not set.
7649 * \throw If the nodal connectivity of cells is not defined.
7650 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
7652 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
7654 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
7655 int spaceDim=getSpaceDimension();
7656 int nbOfCells=getNumberOfCells();
7657 ret->alloc(nbOfCells,spaceDim);
7658 ret->copyStringInfoFrom(*getCoords());
7659 double *ptToFill=ret->getPointer();
7660 const int *nodal=_nodal_connec->getConstPointer();
7661 const int *nodalI=_nodal_connec_index->getConstPointer();
7662 const double *coor=_coords->getConstPointer();
7663 for(int i=0;i<nbOfCells;i++)
7665 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
7666 INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
7673 * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
7674 * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
7676 * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
7677 * DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
7679 * \sa MEDCouplingUMesh::computeCellCenterOfMass
7680 * \throw If \a this is not fully defined (coordinates and connectivity)
7681 * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
7683 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
7685 checkFullyDefined();
7686 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
7687 int spaceDim=getSpaceDimension();
7688 int nbOfCells=getNumberOfCells();
7689 int nbOfNodes=getNumberOfNodes();
7690 ret->alloc(nbOfCells,spaceDim);
7691 double *ptToFill=ret->getPointer();
7692 const int *nodal=_nodal_connec->getConstPointer();
7693 const int *nodalI=_nodal_connec_index->getConstPointer();
7694 const double *coor=_coords->getConstPointer();
7695 for(int i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
7697 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
7698 std::fill(ptToFill,ptToFill+spaceDim,0.);
7699 if(type!=INTERP_KERNEL::NORM_POLYHED)
7701 for(const int *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
7703 if(*conn>=0 && *conn<nbOfNodes)
7704 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
7707 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," << nbOfNodes << ") !";
7708 throw INTERP_KERNEL::Exception(oss.str().c_str());
7711 int nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
7712 if(nbOfNodesInCell>0)
7713 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
7716 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
7717 throw INTERP_KERNEL::Exception(oss.str().c_str());
7722 std::set<int> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
7724 for(std::set<int>::const_iterator it=s.begin();it!=s.end();it++)
7726 if(*it>=0 && *it<nbOfNodes)
7727 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
7730 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," << nbOfNodes << ") !";
7731 throw INTERP_KERNEL::Exception(oss.str().c_str());
7735 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)s.size()));
7738 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
7739 throw INTERP_KERNEL::Exception(oss.str().c_str());
7747 * Returns a new DataArrayDouble holding barycenters of specified cells. The
7748 * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
7749 * are specified via an array of cell ids.
7750 * \warning Validity of the specified cell ids is not checked!
7751 * Valid range is [ 0, \a this->getNumberOfCells() ).
7752 * \param [in] begin - an array of cell ids of interest.
7753 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
7754 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
7755 * end - \a begin ) tuples per \a this->getSpaceDimension() components. The
7756 * caller is to delete this array using decrRef() as it is no more needed.
7757 * \throw If the coordinates array is not set.
7758 * \throw If the nodal connectivity of cells is not defined.
7760 * \if ENABLE_EXAMPLES
7761 * \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
7762 * \ref py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
7765 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const int *begin, const int *end) const
7767 DataArrayDouble *ret=DataArrayDouble::New();
7768 int spaceDim=getSpaceDimension();
7769 int nbOfTuple=(int)std::distance(begin,end);
7770 ret->alloc(nbOfTuple,spaceDim);
7771 double *ptToFill=ret->getPointer();
7772 double *tmp=new double[spaceDim];
7773 const int *nodal=_nodal_connec->getConstPointer();
7774 const int *nodalI=_nodal_connec_index->getConstPointer();
7775 const double *coor=_coords->getConstPointer();
7776 for(const int *w=begin;w!=end;w++)
7778 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
7779 INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
7787 * 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".
7788 * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
7789 * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
7790 * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
7791 * This method is useful to detect 2D cells in 3D space that are not coplanar.
7793 * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
7794 * \throw If spaceDim!=3 or meshDim!=2.
7795 * \throw If connectivity of \a this is invalid.
7796 * \throw If connectivity of a cell in \a this points to an invalid node.
7798 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
7800 MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
7801 int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
7802 if(getSpaceDimension()!=3 || getMeshDimension()!=2)
7803 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
7804 ret->alloc(nbOfCells,4);
7805 double *retPtr(ret->getPointer());
7806 const int *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
7807 const double *coor(_coords->begin());
7808 for(int i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
7810 double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
7811 if(nodalI[1]-nodalI[0]>=3)
7813 for(int j=0;j<3;j++)
7815 int nodeId(nodal[nodalI[0]+1+j]);
7816 if(nodeId>=0 && nodeId<nbOfNodes)
7817 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
7820 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
7821 throw INTERP_KERNEL::Exception(oss.str().c_str());
7827 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
7828 throw INTERP_KERNEL::Exception(oss.str().c_str());
7830 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
7831 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
7837 * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
7840 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
7843 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
7844 da->checkAllocated();
7845 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(da->getName(),0);
7847 int nbOfTuples=da->getNumberOfTuples();
7848 MCAuto<DataArrayInt> c=DataArrayInt::New();
7849 MCAuto<DataArrayInt> cI=DataArrayInt::New();
7850 c->alloc(2*nbOfTuples,1);
7851 cI->alloc(nbOfTuples+1,1);
7852 int *cp=c->getPointer();
7853 int *cip=cI->getPointer();
7855 for(int i=0;i<nbOfTuples;i++)
7857 *cp++=INTERP_KERNEL::NORM_POINT1;
7861 ret->setConnectivity(c,cI,true);
7865 * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
7866 * Cells and nodes of
7867 * the first mesh precede cells and nodes of the second mesh within the result mesh.
7868 * \param [in] mesh1 - the first mesh.
7869 * \param [in] mesh2 - the second mesh.
7870 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7871 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7872 * is no more needed.
7873 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
7874 * \throw If the coordinates array is not set in none of the meshes.
7875 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
7876 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
7878 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
7880 std::vector<const MEDCouplingUMesh *> tmp(2);
7881 tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
7882 return MergeUMeshes(tmp);
7886 * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
7887 * Cells and nodes of
7888 * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
7889 * \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
7890 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7891 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7892 * is no more needed.
7893 * \throw If \a a.size() == 0.
7894 * \throw If \a a[ *i* ] == NULL.
7895 * \throw If the coordinates array is not set in none of the meshes.
7896 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
7897 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
7899 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(std::vector<const MEDCouplingUMesh *>& a)
7901 std::size_t sz=a.size();
7903 return MergeUMeshesLL(a);
7904 for(std::size_t ii=0;ii<sz;ii++)
7907 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
7908 throw INTERP_KERNEL::Exception(oss.str().c_str());
7910 std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
7911 std::vector< const MEDCouplingUMesh * > aa(sz);
7913 for(std::size_t i=0;i<sz && spaceDim==-3;i++)
7915 const MEDCouplingUMesh *cur=a[i];
7916 const DataArrayDouble *coo=cur->getCoords();
7918 spaceDim=coo->getNumberOfComponents();
7921 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
7922 for(std::size_t i=0;i<sz;i++)
7924 bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
7927 return MergeUMeshesLL(aa);
7932 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesLL(std::vector<const MEDCouplingUMesh *>& a)
7935 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : input array must be NON EMPTY !");
7936 std::vector<const MEDCouplingUMesh *>::const_iterator it=a.begin();
7937 int meshDim=(*it)->getMeshDimension();
7938 int nbOfCells=(*it)->getNumberOfCells();
7939 int meshLgth=(*it++)->getNodalConnectivityArrayLen();
7940 for(;it!=a.end();it++)
7942 if(meshDim!=(*it)->getMeshDimension())
7943 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, MergeUMeshes impossible !");
7944 nbOfCells+=(*it)->getNumberOfCells();
7945 meshLgth+=(*it)->getNodalConnectivityArrayLen();
7947 std::vector<const MEDCouplingPointSet *> aps(a.size());
7948 std::copy(a.begin(),a.end(),aps.begin());
7949 MCAuto<DataArrayDouble> pts=MergeNodesArray(aps);
7950 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("merge",meshDim);
7951 ret->setCoords(pts);
7952 MCAuto<DataArrayInt> c=DataArrayInt::New();
7953 c->alloc(meshLgth,1);
7954 int *cPtr=c->getPointer();
7955 MCAuto<DataArrayInt> cI=DataArrayInt::New();
7956 cI->alloc(nbOfCells+1,1);
7957 int *cIPtr=cI->getPointer();
7961 for(it=a.begin();it!=a.end();it++)
7963 int curNbOfCell=(*it)->getNumberOfCells();
7964 const int *curCI=(*it)->_nodal_connec_index->getConstPointer();
7965 const int *curC=(*it)->_nodal_connec->getConstPointer();
7966 cIPtr=std::transform(curCI+1,curCI+curNbOfCell+1,cIPtr,std::bind2nd(std::plus<int>(),offset));
7967 for(int j=0;j<curNbOfCell;j++)
7969 const int *src=curC+curCI[j];
7971 for(;src!=curC+curCI[j+1];src++,cPtr++)
7979 offset+=curCI[curNbOfCell];
7980 offset2+=(*it)->getNumberOfNodes();
7983 ret->setConnectivity(c,cI,true);
7990 * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
7991 * dimension and sharing the node coordinates array.
7992 * All cells of the first mesh precede all cells of the second mesh
7993 * within the result mesh.
7994 * \param [in] mesh1 - the first mesh.
7995 * \param [in] mesh2 - the second mesh.
7996 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7997 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7998 * is no more needed.
7999 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
8000 * \throw If the meshes do not share the node coordinates array.
8001 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
8002 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
8004 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
8006 std::vector<const MEDCouplingUMesh *> tmp(2);
8007 tmp[0]=mesh1; tmp[1]=mesh2;
8008 return MergeUMeshesOnSameCoords(tmp);
8012 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
8013 * dimension and sharing the node coordinates array.
8014 * All cells of the *i*-th mesh precede all cells of the
8015 * (*i*+1)-th mesh within the result mesh.
8016 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
8017 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8018 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8019 * is no more needed.
8020 * \throw If \a a.size() == 0.
8021 * \throw If \a a[ *i* ] == NULL.
8022 * \throw If the meshes do not share the node coordinates array.
8023 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
8024 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
8026 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
8029 throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
8030 for(std::size_t ii=0;ii<meshes.size();ii++)
8033 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
8034 throw INTERP_KERNEL::Exception(oss.str().c_str());
8036 const DataArrayDouble *coords=meshes.front()->getCoords();
8037 int meshDim=meshes.front()->getMeshDimension();
8038 std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
8040 int meshIndexLgth=0;
8041 for(;iter!=meshes.end();iter++)
8043 if(coords!=(*iter)->getCoords())
8044 throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
8045 if(meshDim!=(*iter)->getMeshDimension())
8046 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
8047 meshLgth+=(*iter)->getNodalConnectivityArrayLen();
8048 meshIndexLgth+=(*iter)->getNumberOfCells();
8050 MCAuto<DataArrayInt> nodal=DataArrayInt::New();
8051 nodal->alloc(meshLgth,1);
8052 int *nodalPtr=nodal->getPointer();
8053 MCAuto<DataArrayInt> nodalIndex=DataArrayInt::New();
8054 nodalIndex->alloc(meshIndexLgth+1,1);
8055 int *nodalIndexPtr=nodalIndex->getPointer();
8057 for(iter=meshes.begin();iter!=meshes.end();iter++)
8059 const int *nod=(*iter)->getNodalConnectivity()->getConstPointer();
8060 const int *index=(*iter)->getNodalConnectivityIndex()->getConstPointer();
8061 int nbOfCells=(*iter)->getNumberOfCells();
8062 int meshLgth2=(*iter)->getNodalConnectivityArrayLen();
8063 nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
8064 if(iter!=meshes.begin())
8065 nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind2nd(std::plus<int>(),offset));
8067 nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
8070 MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
8071 ret->setName("merge");
8072 ret->setMeshDimension(meshDim);
8073 ret->setConnectivity(nodal,nodalIndex,true);
8074 ret->setCoords(coords);
8079 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
8080 * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
8081 * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
8082 * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
8083 * New" mode are returned for each input mesh.
8084 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
8085 * \param [in] compType - specifies a cell comparison technique. For meaning of its
8086 * valid values [0,1,2], see zipConnectivityTraducer().
8087 * \param [in,out] corr - an array of DataArrayInt, of the same size as \a
8088 * meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
8089 * mesh. The caller is to delete each of the arrays using decrRef() as it is
8091 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8092 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8093 * is no more needed.
8094 * \throw If \a meshes.size() == 0.
8095 * \throw If \a meshes[ *i* ] == NULL.
8096 * \throw If the meshes do not share the node coordinates array.
8097 * \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
8098 * \throw If the \a meshes are of different dimension (getMeshDimension()).
8099 * \throw If the nodal connectivity of cells of any of \a meshes is not defined.
8100 * \throw If the nodal connectivity any of \a meshes includes an invalid id.
8102 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayInt *>& corr)
8104 //All checks are delegated to MergeUMeshesOnSameCoords
8105 MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
8106 MCAuto<DataArrayInt> o2n=ret->zipConnectivityTraducer(compType);
8107 corr.resize(meshes.size());
8108 std::size_t nbOfMeshes=meshes.size();
8110 const int *o2nPtr=o2n->getConstPointer();
8111 for(std::size_t i=0;i<nbOfMeshes;i++)
8113 DataArrayInt *tmp=DataArrayInt::New();
8114 int curNbOfCells=meshes[i]->getNumberOfCells();
8115 tmp->alloc(curNbOfCells,1);
8116 std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
8117 offset+=curNbOfCells;
8118 tmp->setName(meshes[i]->getName());
8125 * Makes all given meshes share the nodal connectivity array. The common connectivity
8126 * array is created by concatenating the connectivity arrays of all given meshes. All
8127 * the given meshes must be of the same space dimension but dimension of cells **can
8128 * differ**. This method is particulary useful in MEDLoader context to build a \ref
8129 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
8130 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
8131 * \param [in,out] meshes - a vector of meshes to update.
8132 * \throw If any of \a meshes is NULL.
8133 * \throw If the coordinates array is not set in any of \a meshes.
8134 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
8135 * \throw If \a meshes are of different space dimension.
8137 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
8139 std::size_t sz=meshes.size();
8142 std::vector< const DataArrayDouble * > coords(meshes.size());
8143 std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
8144 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
8148 (*it)->checkConnectivityFullyDefined();
8149 const DataArrayDouble *coo=(*it)->getCoords();
8154 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
8155 oss << " has no coordinate array defined !";
8156 throw INTERP_KERNEL::Exception(oss.str().c_str());
8161 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
8162 oss << " is null !";
8163 throw INTERP_KERNEL::Exception(oss.str().c_str());
8166 MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
8167 std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
8168 int offset=(*it)->getNumberOfNodes();
8169 (*it++)->setCoords(res);
8170 for(;it!=meshes.end();it++)
8172 int oldNumberOfNodes=(*it)->getNumberOfNodes();
8173 (*it)->setCoords(res);
8174 (*it)->shiftNodeNumbersInConn(offset);
8175 offset+=oldNumberOfNodes;
8180 * Merges nodes coincident with a given precision within all given meshes that share
8181 * the nodal connectivity array. The given meshes **can be of different** mesh
8182 * dimension. This method is particulary useful in MEDLoader context to build a \ref
8183 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
8184 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
8185 * \param [in,out] meshes - a vector of meshes to update.
8186 * \param [in] eps - the precision used to detect coincident nodes (infinite norm).
8187 * \throw If any of \a meshes is NULL.
8188 * \throw If the \a meshes do not share the same node coordinates array.
8189 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
8191 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
8195 std::set<const DataArrayDouble *> s;
8196 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
8199 s.insert((*it)->getCoords());
8202 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 !";
8203 throw INTERP_KERNEL::Exception(oss.str().c_str());
8208 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 !";
8209 throw INTERP_KERNEL::Exception(oss.str().c_str());
8211 const DataArrayDouble *coo=*(s.begin());
8215 DataArrayInt *comm,*commI;
8216 coo->findCommonTuples(eps,-1,comm,commI);
8217 MCAuto<DataArrayInt> tmp1(comm),tmp2(commI);
8218 int oldNbOfNodes=coo->getNumberOfTuples();
8220 MCAuto<DataArrayInt> o2n=DataArrayInt::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
8221 if(oldNbOfNodes==newNbOfNodes)
8223 MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->getConstPointer(),newNbOfNodes);
8224 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
8226 (*it)->renumberNodesInConn(o2n->getConstPointer());
8227 (*it)->setCoords(newCoords);
8232 * This method takes in input a cell defined by its MEDcouplingUMesh connectivity [ \a connBg , \a connEnd ) and returns its extruded cell by inserting the result at the end of ret.
8233 * \param nbOfNodesPerLev in parameter that specifies the number of nodes of one slice of global dataset
8234 * \param isQuad specifies the policy of connectivity.
8235 * @ret in/out parameter in which the result will be append
8237 void MEDCouplingUMesh::AppendExtrudedCell(const int *connBg, const int *connEnd, int nbOfNodesPerLev, bool isQuad, std::vector<int>& ret)
8239 INTERP_KERNEL::NormalizedCellType flatType=(INTERP_KERNEL::NormalizedCellType)connBg[0];
8240 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(flatType);
8241 ret.push_back(cm.getExtrudedType());
8242 int deltaz=isQuad?2*nbOfNodesPerLev:nbOfNodesPerLev;
8245 case INTERP_KERNEL::NORM_POINT1:
8247 ret.push_back(connBg[1]);
8248 ret.push_back(connBg[1]+nbOfNodesPerLev);
8251 case INTERP_KERNEL::NORM_SEG2:
8253 int conn[4]={connBg[1],connBg[2],connBg[2]+deltaz,connBg[1]+deltaz};
8254 ret.insert(ret.end(),conn,conn+4);
8257 case INTERP_KERNEL::NORM_SEG3:
8259 int conn[8]={connBg[1],connBg[3],connBg[3]+deltaz,connBg[1]+deltaz,connBg[2],connBg[3]+nbOfNodesPerLev,connBg[2]+deltaz,connBg[1]+nbOfNodesPerLev};
8260 ret.insert(ret.end(),conn,conn+8);
8263 case INTERP_KERNEL::NORM_QUAD4:
8265 int conn[8]={connBg[1],connBg[2],connBg[3],connBg[4],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4]+deltaz};
8266 ret.insert(ret.end(),conn,conn+8);
8269 case INTERP_KERNEL::NORM_TRI3:
8271 int conn[6]={connBg[1],connBg[2],connBg[3],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz};
8272 ret.insert(ret.end(),conn,conn+6);
8275 case INTERP_KERNEL::NORM_TRI6:
8277 int conn[15]={connBg[1],connBg[2],connBg[3],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4],connBg[5],connBg[6],connBg[4]+deltaz,connBg[5]+deltaz,connBg[6]+deltaz,
8278 connBg[1]+nbOfNodesPerLev,connBg[2]+nbOfNodesPerLev,connBg[3]+nbOfNodesPerLev};
8279 ret.insert(ret.end(),conn,conn+15);
8282 case INTERP_KERNEL::NORM_QUAD8:
8285 connBg[1],connBg[2],connBg[3],connBg[4],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4]+deltaz,
8286 connBg[5],connBg[6],connBg[7],connBg[8],connBg[5]+deltaz,connBg[6]+deltaz,connBg[7]+deltaz,connBg[8]+deltaz,
8287 connBg[1]+nbOfNodesPerLev,connBg[2]+nbOfNodesPerLev,connBg[3]+nbOfNodesPerLev,connBg[4]+nbOfNodesPerLev
8289 ret.insert(ret.end(),conn,conn+20);
8292 case INTERP_KERNEL::NORM_POLYGON:
8294 std::back_insert_iterator< std::vector<int> > ii(ret);
8295 std::copy(connBg+1,connEnd,ii);
8297 std::reverse_iterator<const int *> rConnBg(connEnd);
8298 std::reverse_iterator<const int *> rConnEnd(connBg+1);
8299 std::transform(rConnBg,rConnEnd,ii,std::bind2nd(std::plus<int>(),deltaz));
8300 std::size_t nbOfRadFaces=std::distance(connBg+1,connEnd);
8301 for(std::size_t i=0;i<nbOfRadFaces;i++)
8304 int conn[4]={connBg[(i+1)%nbOfRadFaces+1],connBg[i+1],connBg[i+1]+deltaz,connBg[(i+1)%nbOfRadFaces+1]+deltaz};
8305 std::copy(conn,conn+4,ii);
8310 throw INTERP_KERNEL::Exception("A flat type has been detected that has not its extruded representation !");
8315 * This static operates only for coords in 3D. The polygon is specfied by its connectivity nodes in [ \a begin , \a end ).
8317 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const int *begin, const int *end, const double *coords)
8320 double v[3]={0.,0.,0.};
8321 std::size_t sz=std::distance(begin,end);
8326 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];
8327 v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
8328 v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
8330 double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
8332 // Try using quadratic points if standard points are degenerated (for example a QPOLYG with two
8333 // SEG3 forming a circle):
8334 if (fabs(ret) < INTERP_KERNEL::DEFAULT_ABS_TOL && isQuadratic)
8336 v[0] = 0.0; v[1] = 0.0; v[2] = 0.0;
8337 for(std::size_t j=0;j<sz;j++)
8339 if (j%2) // current point i is quadratic, next point i+1 is standard
8342 ip1 = (j+1)%sz; // ip1 = "i+1"
8344 else // current point i is standard, next point i+1 is quadratic
8349 v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
8350 v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
8351 v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
8353 ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
8359 * The polyhedron is specfied by its connectivity nodes in [ \a begin , \a end ).
8361 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const int *begin, const int *end, const double *coords)
8363 std::vector<std::pair<int,int> > edges;
8364 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
8365 const int *bgFace=begin;
8366 for(std::size_t i=0;i<nbOfFaces;i++)
8368 const int *endFace=std::find(bgFace+1,end,-1);
8369 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
8370 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8372 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8373 if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
8375 edges.push_back(p1);
8379 return INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)>-EPS_FOR_POLYH_ORIENTATION;
8383 * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
8385 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const int *begin, const int *end, const double *coords)
8387 double vec0[3],vec1[3];
8388 std::size_t sz=std::distance(begin,end);
8390 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
8391 int nbOfNodes=(int)sz/2;
8392 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
8393 const double *pt0=coords+3*begin[0];
8394 const double *pt1=coords+3*begin[nbOfNodes];
8395 vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
8396 return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
8399 void MEDCouplingUMesh::CorrectExtrudedStaticCell(int *begin, int *end)
8401 std::size_t sz=std::distance(begin,end);
8402 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
8403 std::size_t nbOfNodes(sz/2);
8404 std::copy(begin,end,(int *)tmp);
8405 for(std::size_t j=1;j<nbOfNodes;j++)
8407 begin[j]=tmp[nbOfNodes-j];
8408 begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
8412 bool MEDCouplingUMesh::IsTetra4WellOriented(const int *begin, const int *end, const double *coords)
8414 std::size_t sz=std::distance(begin,end);
8416 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
8417 double vec0[3],vec1[3];
8418 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
8419 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];
8420 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;
8423 bool MEDCouplingUMesh::IsPyra5WellOriented(const int *begin, const int *end, const double *coords)
8425 std::size_t sz=std::distance(begin,end);
8427 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
8429 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
8430 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
8431 return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
8435 * 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 )
8436 * 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
8439 * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
8440 * \param [in] coords the coordinates with nb of components exactly equal to 3
8441 * \param [in] begin begin of the nodal connectivity (geometric type included) of a single polyhedron cell
8442 * \param [in] end end of nodal connectivity of a single polyhedron cell (excluded)
8443 * \param [out] res the result is put at the end of the vector without any alteration of the data.
8445 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, const int *begin, const int *end, DataArrayInt *res)
8447 int nbFaces=std::count(begin+1,end,-1)+1;
8448 MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
8449 double *vPtr=v->getPointer();
8450 MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,1);
8451 double *pPtr=p->getPointer();
8452 const int *stFaceConn=begin+1;
8453 for(int i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
8455 const int *endFaceConn=std::find(stFaceConn,end,-1);
8456 ComputeVecAndPtOfFace(eps,coords->getConstPointer(),stFaceConn,endFaceConn,vPtr,pPtr);
8457 stFaceConn=endFaceConn+1;
8459 pPtr=p->getPointer(); vPtr=v->getPointer();
8460 DataArrayInt *comm1=0,*commI1=0;
8461 v->findCommonTuples(eps,-1,comm1,commI1);
8462 MCAuto<DataArrayInt> comm1Auto(comm1),commI1Auto(commI1);
8463 const int *comm1Ptr=comm1->getConstPointer();
8464 const int *commI1Ptr=commI1->getConstPointer();
8465 int nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
8466 res->pushBackSilent((int)INTERP_KERNEL::NORM_POLYHED);
8468 MCAuto<MEDCouplingUMesh> mm=MEDCouplingUMesh::New("",3);
8469 mm->setCoords(const_cast<DataArrayDouble *>(coords)); mm->allocateCells(1); mm->insertNextCell(INTERP_KERNEL::NORM_POLYHED,(int)std::distance(begin+1,end),begin+1);
8470 mm->finishInsertingCells();
8472 for(int i=0;i<nbOfGrps1;i++)
8474 int vecId=comm1Ptr[commI1Ptr[i]];
8475 MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
8476 DataArrayInt *comm2=0,*commI2=0;
8477 tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
8478 MCAuto<DataArrayInt> comm2Auto(comm2),commI2Auto(commI2);
8479 const int *comm2Ptr=comm2->getConstPointer();
8480 const int *commI2Ptr=commI2->getConstPointer();
8481 int nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
8482 for(int j=0;j<nbOfGrps2;j++)
8484 if(commI2Ptr[j+1]-commI2Ptr[j]<=1)
8486 res->insertAtTheEnd(begin,end);
8487 res->pushBackSilent(-1);
8491 int pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
8492 MCAuto<DataArrayInt> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
8493 ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
8494 DataArrayInt *tmp0=DataArrayInt::New(),*tmp1=DataArrayInt::New(),*tmp2=DataArrayInt::New(),*tmp3=DataArrayInt::New();
8495 MCAuto<MEDCouplingUMesh> mm2=mm->buildDescendingConnectivity(tmp0,tmp1,tmp2,tmp3); tmp0->decrRef(); tmp1->decrRef(); tmp2->decrRef(); tmp3->decrRef();
8496 MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(mm2->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
8497 MCAuto<DataArrayInt> idsNodeTmp=mm3->zipCoordsTraducer();
8498 MCAuto<DataArrayInt> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
8499 const int *idsNodePtr=idsNode->getConstPointer();
8500 double center[3]; center[0]=pPtr[pointId]*vPtr[3*vecId]; center[1]=pPtr[pointId]*vPtr[3*vecId+1]; center[2]=pPtr[pointId]*vPtr[3*vecId+2];
8501 double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
8502 double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
8503 if(std::abs(norm)>eps)
8505 double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
8506 mm3->rotate(center,vec,angle);
8508 mm3->changeSpaceDimension(2);
8509 MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
8510 const int *conn4=mm4->getNodalConnectivity()->getConstPointer();
8511 const int *connI4=mm4->getNodalConnectivityIndex()->getConstPointer();
8512 int nbOfCells=mm4->getNumberOfCells();
8513 for(int k=0;k<nbOfCells;k++)
8516 for(const int *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
8517 res->pushBackSilent(idsNodePtr[*work]);
8518 res->pushBackSilent(-1);
8523 res->popBackSilent();
8527 * 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
8528 * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
8530 * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
8531 * \param [in] coords coordinates expected to have 3 components.
8532 * \param [in] begin start of the nodal connectivity of the face.
8533 * \param [in] end end of the nodal connectivity (excluded) of the face.
8534 * \param [out] v the normalized vector of size 3
8535 * \param [out] p the pos of plane
8537 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const int *begin, const int *end, double *v, double *p)
8539 std::size_t nbPoints=std::distance(begin,end);
8541 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
8542 double vec[3]={0.,0.,0.};
8544 bool refFound=false;
8545 for(;j<nbPoints-1 && !refFound;j++)
8547 vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
8548 vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
8549 vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
8550 double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
8554 vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
8557 for(std::size_t i=j;i<nbPoints-1;i++)
8560 curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
8561 curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
8562 curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
8563 double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
8566 curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
8567 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];
8568 norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
8571 v[0]/=norm; v[1]/=norm; v[2]/=norm;
8572 *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
8576 throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
8580 * This method tries to obtain a well oriented polyhedron.
8581 * If the algorithm fails, an exception will be thrown.
8583 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(int *begin, int *end, const double *coords)
8585 std::list< std::pair<int,int> > edgesOK,edgesFinished;
8586 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
8587 std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
8589 int *bgFace=begin,*endFace=std::find(begin+1,end,-1);
8590 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
8591 for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<int,int> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
8593 while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
8596 std::size_t smthChanged=0;
8597 for(std::size_t i=0;i<nbOfFaces;i++)
8599 endFace=std::find(bgFace+1,end,-1);
8600 nbOfEdgesInFace=std::distance(bgFace,endFace);
8604 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8606 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8607 std::pair<int,int> p2(p1.second,p1.first);
8608 bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
8609 bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
8610 if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
8615 std::reverse(bgFace+1,endFace);
8616 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8618 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8619 std::pair<int,int> p2(p1.second,p1.first);
8620 if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
8621 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str().c_str()); }
8622 if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
8623 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str().c_str()); }
8624 std::list< std::pair<int,int> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
8625 if(it!=edgesOK.end())
8628 edgesFinished.push_back(p1);
8631 edgesOK.push_back(p1);
8638 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
8640 if(!edgesOK.empty())
8641 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
8642 if(INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)<-EPS_FOR_POLYH_ORIENTATION)
8643 {//not lucky ! The first face was not correctly oriented : reorient all faces...
8645 for(std::size_t i=0;i<nbOfFaces;i++)
8647 endFace=std::find(bgFace+1,end,-1);
8648 std::reverse(bgFace+1,endFace);
8654 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMeshLinear(const MEDCouplingUMesh *skin, const DataArrayInt *n2o) const
8656 int nbOfNodesExpected(skin->getNumberOfNodes());
8657 const int *n2oPtr(n2o->getConstPointer());
8658 MCAuto<DataArrayInt> revNodal(DataArrayInt::New()),revNodalI(DataArrayInt::New());
8659 skin->getReverseNodalConnectivity(revNodal,revNodalI);
8660 const int *revNodalPtr(revNodal->getConstPointer()),*revNodalIPtr(revNodalI->getConstPointer());
8661 const int *nodalPtr(skin->getNodalConnectivity()->getConstPointer());
8662 const int *nodalIPtr(skin->getNodalConnectivityIndex()->getConstPointer());
8663 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfNodesExpected+1,1);
8664 int *work(ret->getPointer()); *work++=INTERP_KERNEL::NORM_POLYGON;
8665 if(nbOfNodesExpected<1)
8667 int prevCell(0),prevNode(nodalPtr[nodalIPtr[0]+1]);
8668 *work++=n2oPtr[prevNode];
8669 for(int i=1;i<nbOfNodesExpected;i++)
8671 if(nodalIPtr[prevCell+1]-nodalIPtr[prevCell]==3)
8673 std::set<int> conn(nodalPtr+nodalIPtr[prevCell]+1,nodalPtr+nodalIPtr[prevCell]+3);
8674 conn.erase(prevNode);
8677 int curNode(*(conn.begin()));
8678 *work++=n2oPtr[curNode];
8679 std::set<int> shar(revNodalPtr+revNodalIPtr[curNode],revNodalPtr+revNodalIPtr[curNode+1]);
8680 shar.erase(prevCell);
8683 prevCell=*(shar.begin());
8687 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected 2 !");
8690 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected 1 !");
8693 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected cell !");
8698 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMeshQuadratic(const MEDCouplingUMesh *skin, const DataArrayInt *n2o) const
8700 int nbOfNodesExpected(skin->getNumberOfNodes());
8701 int nbOfTurn(nbOfNodesExpected/2);
8702 const int *n2oPtr(n2o->getConstPointer());
8703 MCAuto<DataArrayInt> revNodal(DataArrayInt::New()),revNodalI(DataArrayInt::New());
8704 skin->getReverseNodalConnectivity(revNodal,revNodalI);
8705 const int *revNodalPtr(revNodal->getConstPointer()),*revNodalIPtr(revNodalI->getConstPointer());
8706 const int *nodalPtr(skin->getNodalConnectivity()->getConstPointer());
8707 const int *nodalIPtr(skin->getNodalConnectivityIndex()->getConstPointer());
8708 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfNodesExpected+1,1);
8709 int *work(ret->getPointer()); *work++=INTERP_KERNEL::NORM_QPOLYG;
8710 if(nbOfNodesExpected<1)
8712 int prevCell(0),prevNode(nodalPtr[nodalIPtr[0]+1]);
8713 *work=n2oPtr[prevNode]; work[nbOfTurn]=n2oPtr[nodalPtr[nodalIPtr[0]+3]]; work++;
8714 for(int i=1;i<nbOfTurn;i++)
8716 if(nodalIPtr[prevCell+1]-nodalIPtr[prevCell]==4)
8718 std::set<int> conn(nodalPtr+nodalIPtr[prevCell]+1,nodalPtr+nodalIPtr[prevCell]+3);
8719 conn.erase(prevNode);
8722 int curNode(*(conn.begin()));
8723 *work=n2oPtr[curNode];
8724 std::set<int> shar(revNodalPtr+revNodalIPtr[curNode],revNodalPtr+revNodalIPtr[curNode+1]);
8725 shar.erase(prevCell);
8728 int curCell(*(shar.begin()));
8729 work[nbOfTurn]=n2oPtr[nodalPtr[nodalIPtr[curCell]+3]];
8735 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected 2 !");
8738 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected 1 !");
8741 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected cell !");
8747 * This method makes the assumption spacedimension == meshdimension == 2.
8748 * This method works only for linear cells.
8750 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
8752 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMesh() const
8754 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
8755 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
8756 MCAuto<MEDCouplingUMesh> skin(computeSkin());
8757 int oldNbOfNodes(skin->getNumberOfNodes());
8758 MCAuto<DataArrayInt> o2n(skin->zipCoordsTraducer());
8759 int nbOfNodesExpected(skin->getNumberOfNodes());
8760 MCAuto<DataArrayInt> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
8761 int nbCells(skin->getNumberOfCells());
8762 if(nbCells==nbOfNodesExpected)
8763 return buildUnionOf2DMeshLinear(skin,n2o);
8764 else if(2*nbCells==nbOfNodesExpected)
8765 return buildUnionOf2DMeshQuadratic(skin,n2o);
8767 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
8771 * This method makes the assumption spacedimension == meshdimension == 3.
8772 * This method works only for linear cells.
8774 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
8776 DataArrayInt *MEDCouplingUMesh::buildUnionOf3DMesh() const
8778 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8779 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
8780 MCAuto<MEDCouplingUMesh> m=computeSkin();
8781 const int *conn=m->getNodalConnectivity()->getConstPointer();
8782 const int *connI=m->getNodalConnectivityIndex()->getConstPointer();
8783 int nbOfCells=m->getNumberOfCells();
8784 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
8785 int *work=ret->getPointer(); *work++=INTERP_KERNEL::NORM_POLYHED;
8788 work=std::copy(conn+connI[0]+1,conn+connI[1],work);
8789 for(int i=1;i<nbOfCells;i++)
8792 work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
8798 * \brief Creates a graph of cell neighbors
8799 * \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
8800 * In the sky line array, graph arcs are stored in terms of (index,value) notation.
8802 * - index: 0 3 5 6 6
8803 * - value: 1 2 3 2 3 3
8804 * means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
8805 * Arcs are not doubled but reflexive (1,1) arcs are present for each cell
8807 MEDCouplingSkyLineArray *MEDCouplingUMesh::generateGraph() const
8809 checkConnectivityFullyDefined();
8811 int meshDim = this->getMeshDimension();
8812 MEDCoupling::DataArrayInt* indexr=MEDCoupling::DataArrayInt::New();
8813 MEDCoupling::DataArrayInt* revConn=MEDCoupling::DataArrayInt::New();
8814 this->getReverseNodalConnectivity(revConn,indexr);
8815 const int* indexr_ptr=indexr->getConstPointer();
8816 const int* revConn_ptr=revConn->getConstPointer();
8818 const MEDCoupling::DataArrayInt* index;
8819 const MEDCoupling::DataArrayInt* conn;
8820 conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
8821 index=this->getNodalConnectivityIndex();
8822 int nbCells=this->getNumberOfCells();
8823 const int* index_ptr=index->getConstPointer();
8824 const int* conn_ptr=conn->getConstPointer();
8826 //creating graph arcs (cell to cell relations)
8827 //arcs are stored in terms of (index,value) notation
8830 // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
8831 // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
8833 //warning here one node have less than or equal effective number of cell with it
8834 //but cell could have more than effective nodes
8835 //because other equals nodes in other domain (with other global inode)
8836 std::vector <int> cell2cell_index(nbCells+1,0);
8837 std::vector <int> cell2cell;
8838 cell2cell.reserve(3*nbCells);
8840 for (int icell=0; icell<nbCells;icell++)
8842 std::map<int,int > counter;
8843 for (int iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
8845 int inode=conn_ptr[iconn];
8846 for (int iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
8848 int icell2=revConn_ptr[iconnr];
8849 std::map<int,int>::iterator iter=counter.find(icell2);
8850 if (iter!=counter.end()) (iter->second)++;
8851 else counter.insert(std::make_pair(icell2,1));
8854 for (std::map<int,int>::const_iterator iter=counter.begin();
8855 iter!=counter.end(); iter++)
8856 if (iter->second >= meshDim)
8858 cell2cell_index[icell+1]++;
8859 cell2cell.push_back(iter->first);
8864 cell2cell_index[0]=0;
8865 for (int icell=0; icell<nbCells;icell++)
8866 cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
8868 //filling up index and value to create skylinearray structure
8869 MEDCouplingSkyLineArray* array=new MEDCouplingSkyLineArray(cell2cell_index,cell2cell);
8874 * This method put in zip format into parameter 'zipFrmt' in full interlace mode.
8875 * This format is often asked by INTERP_KERNEL algorithms to avoid many indirections into coordinates array.
8877 void MEDCouplingUMesh::FillInCompact3DMode(int spaceDim, int nbOfNodesInCell, const int *conn, const double *coo, double *zipFrmt)
8881 for(int i=0;i<nbOfNodesInCell;i++)
8882 w=std::copy(coo+3*conn[i],coo+3*conn[i]+3,w);
8883 else if(spaceDim==2)
8885 for(int i=0;i<nbOfNodesInCell;i++)
8887 w=std::copy(coo+2*conn[i],coo+2*conn[i]+2,w);
8892 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::FillInCompact3DMode : Invalid spaceDim specified : must be 2 or 3 !");
8895 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
8897 int nbOfCells=getNumberOfCells();
8899 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
8900 static const int PARAMEDMEM2VTKTYPETRADUCER[INTERP_KERNEL::NORM_MAXTYPE+1]={1,3,21,5,9,7,22,34,23,28,-1,-1,-1,-1,10,14,13,-1,12,-1,24,-1,16,27,-1,26,-1,29,-1,-1,25,42,36,4};
8901 ofs << " <" << getVTKDataSetType() << ">\n";
8902 ofs << " <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
8903 ofs << " <PointData>\n" << pointData << std::endl;
8904 ofs << " </PointData>\n";
8905 ofs << " <CellData>\n" << cellData << std::endl;
8906 ofs << " </CellData>\n";
8907 ofs << " <Points>\n";
8908 if(getSpaceDimension()==3)
8909 _coords->writeVTK(ofs,8,"Points",byteData);
8912 MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
8913 coo->writeVTK(ofs,8,"Points",byteData);
8915 ofs << " </Points>\n";
8916 ofs << " <Cells>\n";
8917 const int *cPtr=_nodal_connec->getConstPointer();
8918 const int *cIPtr=_nodal_connec_index->getConstPointer();
8919 MCAuto<DataArrayInt> faceoffsets=DataArrayInt::New(); faceoffsets->alloc(nbOfCells,1);
8920 MCAuto<DataArrayInt> types=DataArrayInt::New(); types->alloc(nbOfCells,1);
8921 MCAuto<DataArrayInt> offsets=DataArrayInt::New(); offsets->alloc(nbOfCells,1);
8922 MCAuto<DataArrayInt> connectivity=DataArrayInt::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
8923 int *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
8924 int szFaceOffsets=0,szConn=0;
8925 for(int i=0;i<nbOfCells;i++,w1++,w2++,w3++)
8928 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
8931 *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
8932 w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
8936 int deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
8937 *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
8938 std::set<int> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
8939 *w3=szConn+(int)c.size(); szConn+=(int)c.size();
8940 w4=std::copy(c.begin(),c.end(),w4);
8943 types->transformWithIndArr(PARAMEDMEM2VTKTYPETRADUCER,PARAMEDMEM2VTKTYPETRADUCER+INTERP_KERNEL::NORM_MAXTYPE+1);
8944 types->writeVTK(ofs,8,"UInt8","types",byteData);
8945 offsets->writeVTK(ofs,8,"Int32","offsets",byteData);
8946 if(szFaceOffsets!=0)
8947 {//presence of Polyhedra
8948 connectivity->reAlloc(szConn);
8949 faceoffsets->writeVTK(ofs,8,"Int32","faceoffsets",byteData);
8950 MCAuto<DataArrayInt> faces=DataArrayInt::New(); faces->alloc(szFaceOffsets,1);
8951 w1=faces->getPointer();
8952 for(int i=0;i<nbOfCells;i++)
8953 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
8955 int nbFaces=std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1)+1;
8957 const int *w6=cPtr+cIPtr[i]+1,*w5=0;
8958 for(int j=0;j<nbFaces;j++)
8960 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
8961 *w1++=(int)std::distance(w6,w5);
8962 w1=std::copy(w6,w5,w1);
8966 faces->writeVTK(ofs,8,"Int32","faces",byteData);
8968 connectivity->writeVTK(ofs,8,"Int32","connectivity",byteData);
8969 ofs << " </Cells>\n";
8970 ofs << " </Piece>\n";
8971 ofs << " </" << getVTKDataSetType() << ">\n";
8974 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
8976 stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
8978 { stream << " Not set !"; return ; }
8979 stream << " Mesh dimension : " << _mesh_dim << ".";
8983 { stream << " No coordinates set !"; return ; }
8984 if(!_coords->isAllocated())
8985 { stream << " Coordinates set but not allocated !"; return ; }
8986 stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
8987 stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
8988 if(!_nodal_connec_index)
8989 { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
8990 if(!_nodal_connec_index->isAllocated())
8991 { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
8992 int lgth=_nodal_connec_index->getNumberOfTuples();
8993 int cpt=_nodal_connec_index->getNumberOfComponents();
8994 if(cpt!=1 || lgth<1)
8996 stream << std::endl << "Number of cells : " << lgth-1 << ".";
8999 std::string MEDCouplingUMesh::getVTKDataSetType() const
9001 return std::string("UnstructuredGrid");
9004 std::string MEDCouplingUMesh::getVTKFileExtension() const
9006 return std::string("vtu");
9010 * Partitions the first given 2D mesh using the second given 2D mesh as a tool, and
9011 * returns a result mesh constituted by polygons.
9012 * Thus the final result contains all nodes from m1 plus new nodes. However it doesn't necessarily contains
9013 * all nodes from m2.
9014 * The meshes should be in 2D space. In
9015 * addition, returns two arrays mapping cells of the result mesh to cells of the input
9017 * \param [in] m1 - the first input mesh which is a partitioned object. The mesh must be so that each point in the space covered by \a m1
9018 * must be covered exactly by one entity, \b no \b more. If it is not the case, some tools are available to heal the mesh (conformize2D, mergeNodes)
9019 * \param [in] m2 - the second input mesh which is a partition tool. The mesh must be so that each point in the space covered by \a m2
9020 * must be covered exactly by one entity, \b no \b more. If it is not the case, some tools are available to heal the mesh (conformize2D, mergeNodes)
9021 * \param [in] eps - precision used to detect coincident mesh entities.
9022 * \param [out] cellNb1 - a new instance of DataArrayInt holding for each result
9023 * cell an id of the cell of \a m1 it comes from. The caller is to delete
9024 * this array using decrRef() as it is no more needed.
9025 * \param [out] cellNb2 - a new instance of DataArrayInt holding for each result
9026 * cell an id of the cell of \a m2 it comes from. -1 value means that a
9027 * result cell comes from a cell (or part of cell) of \a m1 not overlapped by
9028 * any cell of \a m2. The caller is to delete this array using decrRef() as
9029 * it is no more needed.
9030 * \return MEDCouplingUMesh * - the result 2D mesh which is a new instance of
9031 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
9032 * is no more needed.
9033 * \throw If the coordinates array is not set in any of the meshes.
9034 * \throw If the nodal connectivity of cells is not defined in any of the meshes.
9035 * \throw If any of the meshes is not a 2D mesh in 2D space.
9037 * \sa conformize2D, mergeNodes
9039 MEDCouplingUMesh *MEDCouplingUMesh::Intersect2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2,
9040 double eps, DataArrayInt *&cellNb1, DataArrayInt *&cellNb2)
9043 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshes : input meshes must be not NULL !");
9044 m1->checkFullyDefined();
9045 m2->checkFullyDefined();
9046 if(m1->getMeshDimension()!=2 || m1->getSpaceDimension()!=2 || m2->getMeshDimension()!=2 || m2->getSpaceDimension()!=2)
9047 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshes works on umeshes m1 AND m2 with meshdim equal to 2 and spaceDim equal to 2 too!");
9049 // Step 1: compute all edge intersections (new nodes)
9050 std::vector< std::vector<int> > intersectEdge1, colinear2, subDiv2;
9051 MEDCouplingUMesh *m1Desc=0,*m2Desc=0; // descending connec. meshes
9052 DataArrayInt *desc1=0,*descIndx1=0,*revDesc1=0,*revDescIndx1=0,*desc2=0,*descIndx2=0,*revDesc2=0,*revDescIndx2=0;
9053 std::vector<double> addCoo,addCoordsQuadratic; // coordinates of newly created nodes
9054 IntersectDescending2DMeshes(m1,m2,eps,intersectEdge1,colinear2, subDiv2,
9055 m1Desc,desc1,descIndx1,revDesc1,revDescIndx1,
9056 addCoo, m2Desc,desc2,descIndx2,revDesc2,revDescIndx2);
9057 revDesc1->decrRef(); revDescIndx1->decrRef(); revDesc2->decrRef(); revDescIndx2->decrRef();
9058 MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(desc2),dd4(descIndx2);
9059 MCAuto<MEDCouplingUMesh> dd5(m1Desc),dd6(m2Desc);
9061 // Step 2: re-order newly created nodes according to the ordering found in m2
9062 std::vector< std::vector<int> > intersectEdge2;
9063 BuildIntersectEdges(m1Desc,m2Desc,addCoo,subDiv2,intersectEdge2);
9064 subDiv2.clear(); dd5=0; dd6=0;
9067 std::vector<int> cr,crI; //no DataArrayInt because interface with Geometric2D
9068 std::vector<int> cNb1,cNb2; //no DataArrayInt because interface with Geometric2D
9069 BuildIntersecting2DCellsFromEdges(eps,m1,desc1->getConstPointer(),descIndx1->getConstPointer(),intersectEdge1,colinear2,m2,desc2->getConstPointer(),descIndx2->getConstPointer(),intersectEdge2,addCoo,
9070 /* outputs -> */addCoordsQuadratic,cr,crI,cNb1,cNb2);
9072 // Step 4: Prepare final result:
9073 MCAuto<DataArrayDouble> addCooDa(DataArrayDouble::New());
9074 addCooDa->alloc((int)(addCoo.size())/2,2);
9075 std::copy(addCoo.begin(),addCoo.end(),addCooDa->getPointer());
9076 MCAuto<DataArrayDouble> addCoordsQuadraticDa(DataArrayDouble::New());
9077 addCoordsQuadraticDa->alloc((int)(addCoordsQuadratic.size())/2,2);
9078 std::copy(addCoordsQuadratic.begin(),addCoordsQuadratic.end(),addCoordsQuadraticDa->getPointer());
9079 std::vector<const DataArrayDouble *> coordss(4);
9080 coordss[0]=m1->getCoords(); coordss[1]=m2->getCoords(); coordss[2]=addCooDa; coordss[3]=addCoordsQuadraticDa;
9081 MCAuto<DataArrayDouble> coo(DataArrayDouble::Aggregate(coordss));
9082 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("Intersect2D",2));
9083 MCAuto<DataArrayInt> conn(DataArrayInt::New()); conn->alloc((int)cr.size(),1); std::copy(cr.begin(),cr.end(),conn->getPointer());
9084 MCAuto<DataArrayInt> connI(DataArrayInt::New()); connI->alloc((int)crI.size(),1); std::copy(crI.begin(),crI.end(),connI->getPointer());
9085 MCAuto<DataArrayInt> c1(DataArrayInt::New()); c1->alloc((int)cNb1.size(),1); std::copy(cNb1.begin(),cNb1.end(),c1->getPointer());
9086 MCAuto<DataArrayInt> c2(DataArrayInt::New()); c2->alloc((int)cNb2.size(),1); std::copy(cNb2.begin(),cNb2.end(),c2->getPointer());
9087 ret->setConnectivity(conn,connI,true);
9088 ret->setCoords(coo);
9089 cellNb1=c1.retn(); cellNb2=c2.retn();
9095 bool IsColinearOfACellOf(const std::vector< std::vector<int> >& intersectEdge1, const std::vector<int>& candidates, int start, int stop, int& retVal)
9097 if(candidates.empty())
9099 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
9101 const std::vector<int>& pool(intersectEdge1[*it]);
9102 int tmp[2]; tmp[0]=start; tmp[1]=stop;
9103 if(std::search(pool.begin(),pool.end(),tmp,tmp+2)!=pool.end())
9108 tmp[0]=stop; tmp[1]=start;
9109 if(std::search(pool.begin(),pool.end(),tmp,tmp+2)!=pool.end())
9118 MEDCouplingUMesh *BuildMesh1DCutFrom(const MEDCouplingUMesh *mesh1D, const std::vector< std::vector<int> >& intersectEdge2, const DataArrayDouble *coords1, const std::vector<double>& addCoo, const std::map<int,int>& mergedNodes, const std::vector< std::vector<int> >& colinear2, const std::vector< std::vector<int> >& intersectEdge1,
9119 MCAuto<DataArrayInt>& idsInRetColinear, MCAuto<DataArrayInt>& idsInMesh1DForIdsInRetColinear)
9121 idsInRetColinear=DataArrayInt::New(); idsInRetColinear->alloc(0,1);
9122 idsInMesh1DForIdsInRetColinear=DataArrayInt::New(); idsInMesh1DForIdsInRetColinear->alloc(0,1);
9123 int nCells(mesh1D->getNumberOfCells());
9124 if(nCells!=(int)intersectEdge2.size())
9125 throw INTERP_KERNEL::Exception("BuildMesh1DCutFrom : internal error # 1 !");
9126 const DataArrayDouble *coo2(mesh1D->getCoords());
9127 const int *c(mesh1D->getNodalConnectivity()->begin()),*ci(mesh1D->getNodalConnectivityIndex()->begin());
9128 const double *coo2Ptr(coo2->begin());
9129 int offset1(coords1->getNumberOfTuples());
9130 int offset2(offset1+coo2->getNumberOfTuples());
9131 int offset3(offset2+addCoo.size()/2);
9132 std::vector<double> addCooQuad;
9133 MCAuto<DataArrayInt> cOut(DataArrayInt::New()),ciOut(DataArrayInt::New()); cOut->alloc(0,1); ciOut->alloc(1,1); ciOut->setIJ(0,0,0);
9134 int tmp[4],cicnt(0),kk(0);
9135 for(int i=0;i<nCells;i++)
9137 std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
9138 INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coo2Ptr,m));
9139 const std::vector<int>& subEdges(intersectEdge2[i]);
9140 int nbSubEdge(subEdges.size()/2);
9141 for(int j=0;j<nbSubEdge;j++,kk++)
9143 MCAuto<INTERP_KERNEL::Node> n1(MEDCouplingUMeshBuildQPNode(subEdges[2*j],coords1->begin(),offset1,coo2Ptr,offset2,addCoo)),n2(MEDCouplingUMeshBuildQPNode(subEdges[2*j+1],coords1->begin(),offset1,coo2Ptr,offset2,addCoo));
9144 MCAuto<INTERP_KERNEL::Edge> e2(e->buildEdgeLyingOnMe(n1,n2));
9145 INTERP_KERNEL::Edge *e2Ptr(e2);
9146 std::map<int,int>::const_iterator itm;
9147 if(dynamic_cast<INTERP_KERNEL::EdgeArcCircle *>(e2Ptr))
9149 tmp[0]=INTERP_KERNEL::NORM_SEG3;
9150 itm=mergedNodes.find(subEdges[2*j]);
9151 tmp[1]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j];
9152 itm=mergedNodes.find(subEdges[2*j+1]);
9153 tmp[2]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j+1];
9154 tmp[3]=offset3+(int)addCooQuad.size()/2;
9156 e2->getBarycenter(tmp2); addCooQuad.insert(addCooQuad.end(),tmp2,tmp2+2);
9158 cOut->insertAtTheEnd(tmp,tmp+4);
9159 ciOut->pushBackSilent(cicnt);
9163 tmp[0]=INTERP_KERNEL::NORM_SEG2;
9164 itm=mergedNodes.find(subEdges[2*j]);
9165 tmp[1]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j];
9166 itm=mergedNodes.find(subEdges[2*j+1]);
9167 tmp[2]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j+1];
9169 cOut->insertAtTheEnd(tmp,tmp+3);
9170 ciOut->pushBackSilent(cicnt);
9173 if(IsColinearOfACellOf(intersectEdge1,colinear2[i],tmp[1],tmp[2],tmp00))
9175 idsInRetColinear->pushBackSilent(kk);
9176 idsInMesh1DForIdsInRetColinear->pushBackSilent(tmp00);
9181 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(mesh1D->getName(),1));
9182 ret->setConnectivity(cOut,ciOut,true);
9183 MCAuto<DataArrayDouble> arr3(DataArrayDouble::New());
9184 arr3->useArray(&addCoo[0],false,C_DEALLOC,(int)addCoo.size()/2,2);
9185 MCAuto<DataArrayDouble> arr4(DataArrayDouble::New()); arr4->useArray(&addCooQuad[0],false,C_DEALLOC,(int)addCooQuad.size()/2,2);
9186 std::vector<const DataArrayDouble *> coordss(4);
9187 coordss[0]=coords1; coordss[1]=mesh1D->getCoords(); coordss[2]=arr3; coordss[3]=arr4;
9188 MCAuto<DataArrayDouble> arr(DataArrayDouble::Aggregate(coordss));
9189 ret->setCoords(arr);
9193 MEDCouplingUMesh *BuildRefined2DCellLinear(const DataArrayDouble *coords, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9195 std::vector<int> allEdges;
9196 for(const int *it2(descBg);it2!=descEnd;it2++)
9198 const std::vector<int>& edge1(intersectEdge1[std::abs(*it2)-1]);
9200 allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9202 allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9204 std::size_t nb(allEdges.size());
9206 throw INTERP_KERNEL::Exception("BuildRefined2DCellLinear : internal error 1 !");
9207 std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9208 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
9209 ret->setCoords(coords);
9210 ret->allocateCells(1);
9211 std::vector<int> connOut(nbOfEdgesOf2DCellSplit);
9212 for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9213 connOut[kk]=allEdges[2*kk];
9214 ret->insertNextCell(INTERP_KERNEL::NORM_POLYGON,connOut.size(),&connOut[0]);
9218 MEDCouplingUMesh *BuildRefined2DCellQuadratic(const DataArrayDouble *coords, const MEDCouplingUMesh *mesh2D, int cellIdInMesh2D, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9220 const int *c(mesh2D->getNodalConnectivity()->begin()),*ci(mesh2D->getNodalConnectivityIndex()->begin());
9221 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[cellIdInMesh2D]]));
9223 unsigned sz(cm.getNumberOfSons2(c+ci[cellIdInMesh2D]+1,ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]-1));
9224 if(sz!=std::distance(descBg,descEnd))
9225 throw INTERP_KERNEL::Exception("BuildRefined2DCellQuadratic : internal error 1 !");
9226 INTERP_KERNEL::AutoPtr<int> tmpPtr(new int[ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]]);
9227 std::vector<int> allEdges,centers;
9228 const double *coordsPtr(coords->begin());
9229 MCAuto<DataArrayDouble> addCoo(DataArrayDouble::New()); addCoo->alloc(0,1);
9230 int offset(coords->getNumberOfTuples());
9231 for(const int *it2(descBg);it2!=descEnd;it2++,ii++)
9233 INTERP_KERNEL::NormalizedCellType typeOfSon;
9234 cm.fillSonCellNodalConnectivity2(ii,c+ci[cellIdInMesh2D]+1,ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]-1,tmpPtr,typeOfSon);
9235 const std::vector<int>& edge1(intersectEdge1[std::abs(*it2)-1]);
9237 allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9239 allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9241 centers.push_back(tmpPtr[2]);//special case where no subsplit of edge -> reuse the original center.
9243 {//the current edge has been subsplit -> create corresponding centers.
9244 std::size_t nbOfCentersToAppend(edge1.size()/2);
9245 std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9246 MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpPtr,coordsPtr,m));
9247 std::vector<int>::const_iterator it3(allEdges.end()-edge1.size());
9248 for(std::size_t k=0;k<nbOfCentersToAppend;k++)
9251 const double *aa(coordsPtr+2*(*it3++));
9252 const double *bb(coordsPtr+2*(*it3++));
9253 ee->getMiddleOfPoints(aa,bb,tmpp);
9254 addCoo->insertAtTheEnd(tmpp,tmpp+2);
9255 centers.push_back(offset+k);
9259 std::size_t nb(allEdges.size());
9261 throw INTERP_KERNEL::Exception("BuildRefined2DCellQuadratic : internal error 2 !");
9262 std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9263 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
9265 ret->setCoords(coords);
9268 addCoo->rearrange(2);
9269 addCoo=DataArrayDouble::Aggregate(coords,addCoo);
9270 ret->setCoords(addCoo);
9272 ret->allocateCells(1);
9273 std::vector<int> connOut(nbOfEdgesOf2DCellSplit);
9274 for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9275 connOut[kk]=allEdges[2*kk];
9276 connOut.insert(connOut.end(),centers.begin(),centers.end());
9277 ret->insertNextCell(INTERP_KERNEL::NORM_QPOLYG,connOut.size(),&connOut[0]);
9282 * This method creates a refinement of a cell in \a mesh2D. Those cell is defined by descending connectivity and the sorted subdivided nodal connectivity
9285 * \param [in] mesh2D - The origin 2D mesh. \b Warning \b coords are not those of \a mesh2D. But mesh2D->getCoords()==coords[:mesh2D->getNumberOfNodes()]
9287 MEDCouplingUMesh *BuildRefined2DCell(const DataArrayDouble *coords, const MEDCouplingUMesh *mesh2D, int cellIdInMesh2D, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9289 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(mesh2D->getTypeOfCell(cellIdInMesh2D)));
9290 if(!cm.isQuadratic())
9291 return BuildRefined2DCellLinear(coords,descBg,descEnd,intersectEdge1);
9293 return BuildRefined2DCellQuadratic(coords,mesh2D,cellIdInMesh2D,descBg,descEnd,intersectEdge1);
9296 void AddCellInMesh2D(MEDCouplingUMesh *mesh2D, const std::vector<int>& conn, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edges)
9299 for(std::vector< MCAuto<INTERP_KERNEL::Edge> >::const_iterator it=edges.begin();it!=edges.end();it++)
9301 const INTERP_KERNEL::Edge *ee(*it);
9302 if(dynamic_cast<const INTERP_KERNEL::EdgeArcCircle *>(ee))
9306 mesh2D->insertNextCell(INTERP_KERNEL::NORM_POLYGON,conn.size(),&conn[0]);
9309 const double *coo(mesh2D->getCoords()->begin());
9310 std::size_t sz(conn.size());
9311 std::vector<double> addCoo;
9312 std::vector<int> conn2(conn);
9313 int offset(mesh2D->getNumberOfNodes());
9314 for(std::size_t i=0;i<sz;i++)
9317 edges[(i+1)%sz]->getMiddleOfPoints(coo+2*conn[i],coo+2*conn[(i+1)%sz],tmp);// tony a chier i+1 -> i
9318 addCoo.insert(addCoo.end(),tmp,tmp+2);
9319 conn2.push_back(offset+(int)i);
9321 mesh2D->getCoords()->rearrange(1);
9322 mesh2D->getCoords()->pushBackValsSilent(&addCoo[0],&addCoo[0]+addCoo.size());
9323 mesh2D->getCoords()->rearrange(2);
9324 mesh2D->insertNextCell(INTERP_KERNEL::NORM_QPOLYG,conn2.size(),&conn2[0]);
9329 * \b WARNING edges in out1 coming from \a splitMesh1D are \b NOT oriented because only used for equation of curve.
9331 * This method cuts in 2 parts the input 2D cell given using boundaries description (\a edge1Bis and \a edge1BisPtr) using
9332 * a set of edges defined in \a splitMesh1D.
9334 void BuildMesh2DCutInternal2(const MEDCouplingUMesh *splitMesh1D, const std::vector<int>& edge1Bis, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edge1BisPtr,
9335 std::vector< std::vector<int> >& out0, std::vector< std::vector< MCAuto<INTERP_KERNEL::Edge> > >& out1)
9337 std::size_t nb(edge1Bis.size()/2);
9338 std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9339 int iEnd(splitMesh1D->getNumberOfCells());
9341 throw INTERP_KERNEL::Exception("BuildMesh2DCutInternal2 : internal error ! input 1D mesh must have at least one cell !");
9343 const int *cSplitPtr(splitMesh1D->getNodalConnectivity()->begin()),*ciSplitPtr(splitMesh1D->getNodalConnectivityIndex()->begin());
9344 for(ii=0;ii<nb && edge1Bis[2*ii]!=cSplitPtr[ciSplitPtr[0]+1];ii++);
9345 for(jj=ii;jj<nb && edge1Bis[2*jj+1]!=cSplitPtr[ciSplitPtr[iEnd-1]+2];jj++);
9348 {//the edges splitMesh1D[iStart:iEnd] does not fully cut the current 2D cell -> single output cell
9349 out0.resize(1); out1.resize(1);
9350 std::vector<int>& connOut(out0[0]);
9351 connOut.resize(nbOfEdgesOf2DCellSplit);
9352 std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr(out1[0]);
9353 edgesPtr.resize(nbOfEdgesOf2DCellSplit);
9354 for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9356 connOut[kk]=edge1Bis[2*kk];
9357 edgesPtr[kk]=edge1BisPtr[2*kk];
9362 // [i,iEnd[ contains the
9363 out0.resize(2); out1.resize(2);
9364 std::vector<int>& connOutLeft(out0[0]);
9365 std::vector<int>& connOutRight(out0[1]);//connOutLeft should end with edge1Bis[2*ii] and connOutRight should end with edge1Bis[2*jj+1]
9366 std::vector< MCAuto<INTERP_KERNEL::Edge> >& eleft(out1[0]);
9367 std::vector< MCAuto<INTERP_KERNEL::Edge> >& eright(out1[1]);
9368 for(std::size_t k=ii;k<jj+1;k++)
9369 { connOutLeft.push_back(edge1Bis[2*k+1]); eleft.push_back(edge1BisPtr[2*k+1]); }
9370 std::vector< MCAuto<INTERP_KERNEL::Edge> > ees(iEnd);
9371 for(int ik=0;ik<iEnd;ik++)
9373 std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9374 MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)cSplitPtr[ciSplitPtr[ik]],cSplitPtr+ciSplitPtr[ik]+1,splitMesh1D->getCoords()->begin(),m));
9377 for(int ik=iEnd-1;ik>=0;ik--)
9378 connOutLeft.push_back(cSplitPtr[ciSplitPtr[ik]+1]);
9379 for(std::size_t k=jj+1;k<nbOfEdgesOf2DCellSplit+ii;k++)
9380 { connOutRight.push_back(edge1Bis[2*k+1]); eright.push_back(edge1BisPtr[2*k+1]); }
9381 eleft.insert(eleft.end(),ees.rbegin(),ees.rend());
9382 for(int ik=0;ik<iEnd;ik++)
9383 connOutRight.push_back(cSplitPtr[ciSplitPtr[ik]+2]);
9384 eright.insert(eright.end(),ees.begin(),ees.end());
9396 CellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr);
9398 std::vector<int> _edges;
9399 std::vector< MCAuto<INTERP_KERNEL::Edge> > _edges_ptr;
9402 CellInfo::CellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr)
9404 std::size_t nbe(edges.size());
9405 std::vector<int> edges2(2*nbe); std::vector< MCAuto<INTERP_KERNEL::Edge> > edgesPtr2(2*nbe);
9406 for(std::size_t i=0;i<nbe;i++)
9408 edges2[2*i]=edges[i]; edges2[2*i+1]=edges[(i+1)%nbe];
9409 edgesPtr2[2*i]=edgesPtr[(i+1)%nbe]; edgesPtr2[2*i+1]=edgesPtr[(i+1)%nbe];//tony a chier
9411 _edges.resize(4*nbe); _edges_ptr.resize(4*nbe);
9412 std::copy(edges2.begin(),edges2.end(),_edges.begin()); std::copy(edges2.begin(),edges2.end(),_edges.begin()+2*nbe);
9413 std::copy(edgesPtr2.begin(),edgesPtr2.end(),_edges_ptr.begin()); std::copy(edgesPtr2.begin(),edgesPtr2.end(),_edges_ptr.begin()+2*nbe);
9419 EdgeInfo(int istart, int iend, const MCAuto<MEDCouplingUMesh>& mesh):_istart(istart),_iend(iend),_mesh(mesh),_left(-7),_right(-7) { }
9420 EdgeInfo(int istart, int iend, int pos, const MCAuto<INTERP_KERNEL::Edge>& edge):_istart(istart),_iend(iend),_edge(edge),_left(pos),_right(pos+1) { }
9421 bool isInMyRange(int pos) const { return pos>=_istart && pos<_iend; }
9422 void somethingHappendAt(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight);
9423 void feedEdgeInfoAt(double eps, const MEDCouplingUMesh *mesh2D, int offset, int neighbors[2]) const;
9427 MCAuto<MEDCouplingUMesh> _mesh;
9428 MCAuto<INTERP_KERNEL::Edge> _edge;
9433 void EdgeInfo::somethingHappendAt(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight)
9435 const MEDCouplingUMesh *mesh(_mesh);
9441 { _left++; _right++; return ; }
9444 bool isLeft(std::find(newLeft.begin(),newLeft.end(),_edge)!=newLeft.end()),isRight(std::find(newRight.begin(),newRight.end(),_edge)!=newRight.end());
9445 if((isLeft && isRight) || (!isLeft && !isRight))
9446 throw INTERP_KERNEL::Exception("EdgeInfo::somethingHappendAt : internal error # 1 !");
9457 bool isLeft(std::find(newLeft.begin(),newLeft.end(),_edge)!=newLeft.end()),isRight(std::find(newRight.begin(),newRight.end(),_edge)!=newRight.end());
9458 if((isLeft && isRight) || (!isLeft && !isRight))
9459 throw INTERP_KERNEL::Exception("EdgeInfo::somethingHappendAt : internal error # 2 !");
9474 void EdgeInfo::feedEdgeInfoAt(double eps, const MEDCouplingUMesh *mesh2D, int offset, int neighbors[2]) const
9476 const MEDCouplingUMesh *mesh(_mesh);
9479 neighbors[0]=offset+_left; neighbors[1]=offset+_right;
9482 {// not fully splitting cell case
9483 if(mesh2D->getNumberOfCells()==1)
9484 {//little optimization. 1 cell no need to find in which cell mesh is !
9485 neighbors[0]=offset; neighbors[1]=offset;
9490 MCAuto<DataArrayDouble> barys(mesh->computeCellCenterOfMass());
9491 int cellId(mesh2D->getCellContainingPoint(barys->begin(),eps));
9493 throw INTERP_KERNEL::Exception("EdgeInfo::feedEdgeInfoAt : internal error !");
9494 neighbors[0]=offset+cellId; neighbors[1]=offset+cellId;
9499 class VectorOfCellInfo
9502 VectorOfCellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr);
9503 std::size_t size() const { return _pool.size(); }
9504 int getPositionOf(double eps, const MEDCouplingUMesh *mesh) const;
9505 void setMeshAt(int pos, const MCAuto<MEDCouplingUMesh>& mesh, int istart, int iend, const MCAuto<MEDCouplingUMesh>& mesh1DInCase, const std::vector< std::vector<int> >& edges, const std::vector< std::vector< MCAuto<INTERP_KERNEL::Edge> > >& edgePtrs);
9506 const std::vector<int>& getConnOf(int pos) const { return get(pos)._edges; }
9507 const std::vector< MCAuto<INTERP_KERNEL::Edge> >& getEdgePtrOf(int pos) const { return get(pos)._edges_ptr; }
9508 MCAuto<MEDCouplingUMesh> getZeMesh() const { return _ze_mesh; }
9509 void feedEdgeInfoAt(double eps, int pos, int offset, int neighbors[2]) const;
9511 int getZePosOfEdgeGivenItsGlobalId(int pos) const;
9512 void updateEdgeInfo(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight);
9513 const CellInfo& get(int pos) const;
9514 CellInfo& get(int pos);
9516 std::vector<CellInfo> _pool;
9517 MCAuto<MEDCouplingUMesh> _ze_mesh;
9518 std::vector<EdgeInfo> _edge_info;
9521 VectorOfCellInfo::VectorOfCellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr):_pool(1)
9523 _pool[0]._edges=edges;
9524 _pool[0]._edges_ptr=edgesPtr;
9527 int VectorOfCellInfo::getPositionOf(double eps, const MEDCouplingUMesh *mesh) const
9530 throw INTERP_KERNEL::Exception("VectorOfCellSplitter::getPositionOf : empty !");
9533 const MEDCouplingUMesh *zeMesh(_ze_mesh);
9535 throw INTERP_KERNEL::Exception("VectorOfCellSplitter::getPositionOf : null aggregated mesh !");
9536 MCAuto<DataArrayDouble> barys(mesh->computeCellCenterOfMass());
9537 return zeMesh->getCellContainingPoint(barys->begin(),eps);
9540 void VectorOfCellInfo::setMeshAt(int pos, const MCAuto<MEDCouplingUMesh>& mesh, int istart, int iend, const MCAuto<MEDCouplingUMesh>& mesh1DInCase, const std::vector< std::vector<int> >& edges, const std::vector< std::vector< MCAuto<INTERP_KERNEL::Edge> > >& edgePtrs)
9542 get(pos);//to check pos
9543 bool isFast(pos==0 && _pool.size()==1);
9544 std::size_t sz(edges.size());
9545 // dealing with edges
9547 _edge_info.push_back(EdgeInfo(istart,iend,mesh1DInCase));
9549 _edge_info.push_back(EdgeInfo(istart,iend,pos,edgePtrs[0].back()));
9551 std::vector<CellInfo> pool(_pool.size()-1+sz);
9552 for(int i=0;i<pos;i++)
9554 for(std::size_t j=0;j<sz;j++)
9555 pool[pos+j]=CellInfo(edges[j],edgePtrs[j]);
9556 for(int i=pos+1;i<(int)_pool.size();i++)
9557 pool[i+sz-1]=_pool[i];
9561 updateEdgeInfo(pos,edgePtrs[0],edgePtrs[1]);
9569 std::vector< MCAuto<MEDCouplingUMesh> > ms;
9572 MCAuto<MEDCouplingUMesh> elt(static_cast<MEDCouplingUMesh *>(_ze_mesh->buildPartOfMySelfSlice(0,pos,true)));
9576 if(pos<_ze_mesh->getNumberOfCells()-1)
9578 MCAuto<MEDCouplingUMesh> elt(static_cast<MEDCouplingUMesh *>(_ze_mesh->buildPartOfMySelfSlice(pos+1,_ze_mesh->getNumberOfCells(),true)));
9581 std::vector< const MEDCouplingUMesh *> ms2(ms.size());
9582 for(std::size_t j=0;j<ms2.size();j++)
9584 _ze_mesh=MEDCouplingUMesh::MergeUMeshesOnSameCoords(ms2);
9587 void VectorOfCellInfo::feedEdgeInfoAt(double eps, int pos, int offset, int neighbors[2]) const
9589 _edge_info[getZePosOfEdgeGivenItsGlobalId(pos)].feedEdgeInfoAt(eps,_ze_mesh,offset,neighbors);
9592 int VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId(int pos) const
9595 throw INTERP_KERNEL::Exception("VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId : invalid id ! Must be >=0 !");
9597 for(std::vector<EdgeInfo>::const_iterator it=_edge_info.begin();it!=_edge_info.end();it++,ret++)
9599 if((*it).isInMyRange(pos))
9602 throw INTERP_KERNEL::Exception("VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId : invalid id !");
9605 void VectorOfCellInfo::updateEdgeInfo(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight)
9607 get(pos);//to check;
9608 if(_edge_info.empty())
9610 std::size_t sz(_edge_info.size()-1);
9611 for(std::size_t i=0;i<sz;i++)
9612 _edge_info[i].somethingHappendAt(pos,newLeft,newRight);
9615 const CellInfo& VectorOfCellInfo::get(int pos) const
9617 if(pos<0 || pos>=(int)_pool.size())
9618 throw INTERP_KERNEL::Exception("VectorOfCellSplitter::get const : invalid pos !");
9622 CellInfo& VectorOfCellInfo::get(int pos)
9624 if(pos<0 || pos>=(int)_pool.size())
9625 throw INTERP_KERNEL::Exception("VectorOfCellSplitter::get : invalid pos !");
9631 * - a \b closed set of edges ( \a allEdges and \a allEdgesPtr ) that defines the split descending 2D cell.
9632 * - \a splitMesh1D a split 2D curve mesh contained into 2D cell defined above.
9634 * This method returns the 2D mesh and feeds \a idsLeftRight using offset.
9636 * Algorithm : \a splitMesh1D is cut into contiguous parts. Each contiguous parts will build incrementally the output 2D cells.
9638 * \param [in] allEdges a list of pairs (beginNode, endNode). Linked with \a allEdgesPtr to get the equation of edge.
9640 MEDCouplingUMesh *BuildMesh2DCutInternal(double eps, const MEDCouplingUMesh *splitMesh1D, const std::vector<int>& allEdges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& allEdgesPtr, int offset,
9641 MCAuto<DataArrayInt>& idsLeftRight)
9643 int nbCellsInSplitMesh1D(splitMesh1D->getNumberOfCells());
9644 if(nbCellsInSplitMesh1D==0)
9645 throw INTERP_KERNEL::Exception("BuildMesh2DCutInternal : internal error ! input 1D mesh must have at least one cell !");
9646 const int *cSplitPtr(splitMesh1D->getNodalConnectivity()->begin()),*ciSplitPtr(splitMesh1D->getNodalConnectivityIndex()->begin());
9647 std::size_t nb(allEdges.size()),jj;
9649 throw INTERP_KERNEL::Exception("BuildMesh2DCutFrom : internal error 2 !");
9650 std::vector<int> edge1Bis(nb*2);
9651 std::vector< MCAuto<INTERP_KERNEL::Edge> > edge1BisPtr(nb*2);
9652 std::copy(allEdges.begin(),allEdges.end(),edge1Bis.begin());
9653 std::copy(allEdges.begin(),allEdges.end(),edge1Bis.begin()+nb);
9654 std::copy(allEdgesPtr.begin(),allEdgesPtr.end(),edge1BisPtr.begin());
9655 std::copy(allEdgesPtr.begin(),allEdgesPtr.end(),edge1BisPtr.begin()+nb);
9657 idsLeftRight=DataArrayInt::New(); idsLeftRight->alloc(nbCellsInSplitMesh1D*2); idsLeftRight->fillWithValue(-2); idsLeftRight->rearrange(2);
9658 int *idsLeftRightPtr(idsLeftRight->getPointer());
9659 VectorOfCellInfo pool(edge1Bis,edge1BisPtr);
9660 for(int iStart=0;iStart<nbCellsInSplitMesh1D;)
9661 {// split [0:nbCellsInSplitMesh1D) in contiguous parts [iStart:iEnd)
9663 for(;iEnd<nbCellsInSplitMesh1D;)
9665 for(jj=0;jj<nb && edge1Bis[2*jj+1]!=cSplitPtr[ciSplitPtr[iEnd]+2];jj++);
9671 if(iEnd<nbCellsInSplitMesh1D)
9674 MCAuto<MEDCouplingUMesh> partOfSplitMesh1D(static_cast<MEDCouplingUMesh *>(splitMesh1D->buildPartOfMySelfSlice(iStart,iEnd,1,true)));
9675 int pos(pool.getPositionOf(eps,partOfSplitMesh1D));
9677 MCAuto<MEDCouplingUMesh>retTmp(MEDCouplingUMesh::New("",2));
9678 retTmp->setCoords(splitMesh1D->getCoords());
9679 retTmp->allocateCells();
9681 std::vector< std::vector<int> > out0;
9682 std::vector< std::vector< MCAuto<INTERP_KERNEL::Edge> > > out1;
9684 BuildMesh2DCutInternal2(partOfSplitMesh1D,pool.getConnOf(pos),pool.getEdgePtrOf(pos),out0,out1);
9685 for(std::size_t cnt=0;cnt<out0.size();cnt++)
9686 AddCellInMesh2D(retTmp,out0[cnt],out1[cnt]);
9687 pool.setMeshAt(pos,retTmp,iStart,iEnd,partOfSplitMesh1D,out0,out1);
9691 for(int mm=0;mm<nbCellsInSplitMesh1D;mm++)
9692 pool.feedEdgeInfoAt(eps,mm,offset,idsLeftRightPtr+2*mm);
9693 return pool.getZeMesh().retn();
9696 MEDCouplingUMesh *BuildMesh2DCutFrom(double eps, int cellIdInMesh2D, const MEDCouplingUMesh *mesh2DDesc, const MEDCouplingUMesh *splitMesh1D,
9697 const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1, int offset,
9698 MCAuto<DataArrayInt>& idsLeftRight)
9700 const int *cdescPtr(mesh2DDesc->getNodalConnectivity()->begin()),*cidescPtr(mesh2DDesc->getNodalConnectivityIndex()->begin());
9702 std::vector<int> allEdges;
9703 std::vector< MCAuto<INTERP_KERNEL::Edge> > allEdgesPtr; // for each sub edge in splitMesh2D the uncut Edge object of the original mesh2D
9704 for(const int *it(descBg);it!=descEnd;it++) // for all edges in the descending connectivity of the 2D mesh in relative Fortran mode
9706 int edgeId(std::abs(*it)-1);
9707 std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9708 MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)cdescPtr[cidescPtr[edgeId]],cdescPtr+cidescPtr[edgeId]+1,mesh2DDesc->getCoords()->begin(),m));
9709 const std::vector<int>& edge1(intersectEdge1[edgeId]);
9711 allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9713 allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9714 std::size_t sz(edge1.size());
9715 for(std::size_t cnt=0;cnt<sz;cnt++)
9716 allEdgesPtr.push_back(ee);
9719 return BuildMesh2DCutInternal(eps,splitMesh1D,allEdges,allEdgesPtr,offset,idsLeftRight);
9722 bool AreEdgeEqual(const double *coo2D, const INTERP_KERNEL::CellModel& typ1, const int *conn1, const INTERP_KERNEL::CellModel& typ2, const int *conn2, double eps)
9724 if(!typ1.isQuadratic() && !typ2.isQuadratic())
9725 {//easy case comparison not
9726 return conn1[0]==conn2[0] && conn1[1]==conn2[1];
9728 else if(typ1.isQuadratic() && typ2.isQuadratic())
9730 bool status0(conn1[0]==conn2[0] && conn1[1]==conn2[1]);
9733 if(conn1[2]==conn2[2])
9735 const double *a(coo2D+2*conn1[2]),*b(coo2D+2*conn2[2]);
9736 double dist(sqrt((a[0]-b[0])*(a[0]-b[0])+(a[1]-b[1])*(a[1]-b[1])));
9740 {//only one is quadratic
9741 bool status0(conn1[0]==conn2[0] && conn1[1]==conn2[1]);
9744 const double *a(0),*bb(0),*be(0);
9745 if(typ1.isQuadratic())
9747 a=coo2D+2*conn1[2]; bb=coo2D+2*conn2[0]; be=coo2D+2*conn2[1];
9751 a=coo2D+2*conn2[2]; bb=coo2D+2*conn1[0]; be=coo2D+2*conn1[1];
9753 double b[2]; b[0]=(be[0]+bb[0])/2.; b[1]=(be[1]+bb[1])/2.;
9754 double dist(sqrt((a[0]-b[0])*(a[0]-b[0])+(a[1]-b[1])*(a[1]-b[1])));
9760 * This method returns among the cellIds [ \a candidatesIn2DBg , \a candidatesIn2DEnd ) in \a mesh2DSplit those exactly sharing \a cellIdInMesh1DSplitRelative in \a mesh1DSplit.
9761 * \a mesh2DSplit and \a mesh1DSplit are expected to share the coordinates array.
9763 * \param [in] cellIdInMesh1DSplitRelative is in Fortran mode using sign to specify direction.
9765 int FindRightCandidateAmong(const MEDCouplingUMesh *mesh2DSplit, const int *candidatesIn2DBg, const int *candidatesIn2DEnd, const MEDCouplingUMesh *mesh1DSplit, int cellIdInMesh1DSplitRelative, double eps)
9767 if(candidatesIn2DEnd==candidatesIn2DBg)
9768 throw INTERP_KERNEL::Exception("FindRightCandidateAmong : internal error 1 !");
9769 const double *coo(mesh2DSplit->getCoords()->begin());
9770 if(std::distance(candidatesIn2DBg,candidatesIn2DEnd)==1)
9771 return *candidatesIn2DBg;
9772 int edgeId(std::abs(cellIdInMesh1DSplitRelative)-1);
9773 MCAuto<MEDCouplingUMesh> cur1D(static_cast<MEDCouplingUMesh *>(mesh1DSplit->buildPartOfMySelf(&edgeId,&edgeId+1,true)));
9774 if(cellIdInMesh1DSplitRelative<0)
9775 cur1D->changeOrientationOfCells();
9776 const int *c1D(cur1D->getNodalConnectivity()->begin());
9777 const INTERP_KERNEL::CellModel& ref1DType(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c1D[0]));
9778 for(const int *it=candidatesIn2DBg;it!=candidatesIn2DEnd;it++)
9780 MCAuto<MEDCouplingUMesh> cur2D(static_cast<MEDCouplingUMesh *>(mesh2DSplit->buildPartOfMySelf(it,it+1,true)));
9781 const int *c(cur2D->getNodalConnectivity()->begin()),*ci(cur2D->getNodalConnectivityIndex()->begin());
9782 const INTERP_KERNEL::CellModel &cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[0]]));
9783 unsigned sz(cm.getNumberOfSons2(c+ci[0]+1,ci[1]-ci[0]-1));
9784 INTERP_KERNEL::AutoPtr<int> tmpPtr(new int[ci[1]-ci[0]]);
9785 for(unsigned it2=0;it2<sz;it2++)
9787 INTERP_KERNEL::NormalizedCellType typeOfSon;
9788 cm.fillSonCellNodalConnectivity2(it2,c+ci[0]+1,ci[1]-ci[0]-1,tmpPtr,typeOfSon);
9789 const INTERP_KERNEL::CellModel &curCM(INTERP_KERNEL::CellModel::GetCellModel(typeOfSon));
9790 if(AreEdgeEqual(coo,ref1DType,c1D+1,curCM,tmpPtr,eps))
9794 throw INTERP_KERNEL::Exception("FindRightCandidateAmong : internal error 2 ! Unable to find the edge among split cell !");
9800 * Partitions the first given 2D mesh using the second given 1D mesh as a tool.
9801 * Thus the final result contains the aggregation of nodes of \a mesh2D, then nodes of \a mesh1D, then new nodes that are the result of the intersection
9802 * and finaly, in case of quadratic polygon the centers of edges new nodes.
9803 * The meshes should be in 2D space. In addition, returns two arrays mapping cells of the resulting mesh to cells of the input.
9805 * \param [in] mesh2D - the 2D mesh (spacedim=meshdim=2) to be intersected using \a mesh1D tool. The mesh must be so that each point in the space covered by \a mesh2D
9806 * must be covered exactly by one entity, \b no \b more. If it is not the case, some tools are available to heal the mesh (conformize2D, mergeNodes)
9807 * \param [in] mesh1D - the 1D mesh (spacedim=2 meshdim=1) the is the tool that will be used to intersect \a mesh2D. \a mesh1D must be ordered consecutively. If it is not the case
9808 * you can invoke orderConsecutiveCells1D on \a mesh1D.
9809 * \param [in] eps - precision used to perform intersections and localization operations.
9810 * \param [out] splitMesh2D - the result of the split of \a mesh2D mesh.
9811 * \param [out] splitMesh1D - the result of the split of \a mesh1D mesh.
9812 * \param [out] cellIdInMesh2D - the array that gives for each cell id \a i in \a splitMesh2D the id in \a mesh2D it comes from.
9813 * So this array has a number of tuples equal to the number of cells of \a splitMesh2D and a number of component equal to 1.
9814 * \param [out] cellIdInMesh1D - the array of pair that gives for each cell id \a i in \a splitMesh1D the cell in \a splitMesh2D on the left for the 1st component
9815 * and the cell in \a splitMesh2D on the right for the 2nt component. -1 means no cell.
9816 * So this array has a number of tuples equal to the number of cells of \a splitMesh1D and a number of components equal to 2.
9818 * \sa Intersect2DMeshes, orderConsecutiveCells1D, conformize2D, mergeNodes
9820 void MEDCouplingUMesh::Intersect2DMeshWith1DLine(const MEDCouplingUMesh *mesh2D, const MEDCouplingUMesh *mesh1D, double eps, MEDCouplingUMesh *&splitMesh2D, MEDCouplingUMesh *&splitMesh1D, DataArrayInt *&cellIdInMesh2D, DataArrayInt *&cellIdInMesh1D)
9822 if(!mesh2D || !mesh1D)
9823 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshWith1DLine : input meshes must be not NULL !");
9824 mesh2D->checkFullyDefined();
9825 mesh1D->checkFullyDefined();
9826 const std::vector<std::string>& compNames(mesh2D->getCoords()->getInfoOnComponents());
9827 if(mesh2D->getMeshDimension()!=2 || mesh2D->getSpaceDimension()!=2 || mesh1D->getMeshDimension()!=1 || mesh1D->getSpaceDimension()!=2)
9828 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshWith1DLine works with mesh2D with spacedim=meshdim=2 and mesh1D with meshdim=1 spaceDim=2 !");
9829 // Step 1: compute all edge intersections (new nodes)
9830 std::vector< std::vector<int> > intersectEdge1, colinear2, subDiv2;
9831 std::vector<double> addCoo,addCoordsQuadratic; // coordinates of newly created nodes
9832 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
9833 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
9835 // Build desc connectivity
9836 DataArrayInt *desc1(DataArrayInt::New()),*descIndx1(DataArrayInt::New()),*revDesc1(DataArrayInt::New()),*revDescIndx1(DataArrayInt::New());
9837 MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(revDesc1),dd4(revDescIndx1);
9838 MCAuto<MEDCouplingUMesh> m1Desc(mesh2D->buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1));
9839 std::map<int,int> mergedNodes;
9840 Intersect1DMeshes(m1Desc,mesh1D,eps,intersectEdge1,colinear2,subDiv2,addCoo,mergedNodes);
9841 // use mergeNodes to fix intersectEdge1
9842 for(std::vector< std::vector<int> >::iterator it0=intersectEdge1.begin();it0!=intersectEdge1.end();it0++)
9844 std::size_t n((*it0).size()/2);
9845 int eltStart((*it0)[0]),eltEnd((*it0)[2*n-1]);
9846 std::map<int,int>::const_iterator it1;
9847 it1=mergedNodes.find(eltStart);
9848 if(it1!=mergedNodes.end())
9849 (*it0)[0]=(*it1).second;
9850 it1=mergedNodes.find(eltEnd);
9851 if(it1!=mergedNodes.end())
9852 (*it0)[2*n-1]=(*it1).second;
9855 MCAuto<DataArrayDouble> addCooDa(DataArrayDouble::New());
9856 addCooDa->useArray(&addCoo[0],false,C_DEALLOC,(int)addCoo.size()/2,2);
9857 // Step 2: re-order newly created nodes according to the ordering found in m2
9858 std::vector< std::vector<int> > intersectEdge2;
9859 BuildIntersectEdges(m1Desc,mesh1D,addCoo,subDiv2,intersectEdge2);
9861 // Step 3: compute splitMesh1D
9862 MCAuto<DataArrayInt> idsInRet1Colinear,idsInDescMesh2DForIdsInRetColinear;
9863 MCAuto<DataArrayInt> ret2(DataArrayInt::New()); ret2->alloc(0,1);
9864 MCAuto<MEDCouplingUMesh> ret1(BuildMesh1DCutFrom(mesh1D,intersectEdge2,mesh2D->getCoords(),addCoo,mergedNodes,colinear2,intersectEdge1,
9865 idsInRet1Colinear,idsInDescMesh2DForIdsInRetColinear));
9866 MCAuto<DataArrayInt> ret3(DataArrayInt::New()); ret3->alloc(ret1->getNumberOfCells()*2,1); ret3->fillWithValue(std::numeric_limits<int>::max()); ret3->rearrange(2);
9867 MCAuto<DataArrayInt> idsInRet1NotColinear(idsInRet1Colinear->buildComplement(ret1->getNumberOfCells()));
9868 // deal with cells in mesh2D that are not cut but only some of their edges are
9869 MCAuto<DataArrayInt> idsInDesc2DToBeRefined(idsInDescMesh2DForIdsInRetColinear->deepCopy());
9870 idsInDesc2DToBeRefined->abs(); idsInDesc2DToBeRefined->applyLin(1,-1);
9871 idsInDesc2DToBeRefined=idsInDesc2DToBeRefined->buildUnique();
9872 MCAuto<DataArrayInt> out0s;//ids in mesh2D that are impacted by the fact that some edges of \a mesh1D are part of the edges of those cells
9873 if(!idsInDesc2DToBeRefined->empty())
9875 DataArrayInt *out0(0),*outi0(0);
9876 MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
9877 MCAuto<DataArrayInt> outi0s(outi0);
9879 out0s=out0s->buildUnique();
9883 MCAuto<MEDCouplingUMesh> ret1NonCol(static_cast<MEDCouplingUMesh *>(ret1->buildPartOfMySelf(idsInRet1NotColinear->begin(),idsInRet1NotColinear->end())));
9884 MCAuto<DataArrayDouble> baryRet1(ret1NonCol->computeCellCenterOfMass());
9885 MCAuto<DataArrayInt> elts,eltsIndex;
9886 mesh2D->getCellsContainingPoints(baryRet1->begin(),baryRet1->getNumberOfTuples(),eps,elts,eltsIndex);
9887 MCAuto<DataArrayInt> eltsIndex2(eltsIndex->deltaShiftIndex());
9888 MCAuto<DataArrayInt> eltsIndex3(eltsIndex2->findIdsEqual(1));
9889 if(eltsIndex2->count(0)+eltsIndex3->getNumberOfTuples()!=ret1NonCol->getNumberOfCells())
9890 throw INTERP_KERNEL::Exception("Intersect2DMeshWith1DLine : internal error 1 !");
9891 MCAuto<DataArrayInt> cellsToBeModified(elts->buildUnique());
9892 MCAuto<DataArrayInt> untouchedCells(cellsToBeModified->buildComplement(mesh2D->getNumberOfCells()));
9893 if((DataArrayInt *)out0s)
9894 untouchedCells=untouchedCells->buildSubstraction(out0s);//if some edges in ret1 are colinear to descending mesh of mesh2D remove cells from untouched one
9895 std::vector< MCAuto<MEDCouplingUMesh> > outMesh2DSplit;
9896 // OK all is ready to insert in ret2 mesh
9897 if(!untouchedCells->empty())
9898 {// the most easy part, cells in mesh2D not impacted at all
9899 outMesh2DSplit.push_back(static_cast<MEDCouplingUMesh *>(mesh2D->buildPartOfMySelf(untouchedCells->begin(),untouchedCells->end())));
9900 outMesh2DSplit.back()->setCoords(ret1->getCoords());
9901 ret2->pushBackValsSilent(untouchedCells->begin(),untouchedCells->end());
9903 if((DataArrayInt *)out0s)
9904 {// here dealing with cells in out0s but not in cellsToBeModified
9905 MCAuto<DataArrayInt> fewModifiedCells(out0s->buildSubstraction(cellsToBeModified));
9906 const int *rdptr(dd3->begin()),*rdiptr(dd4->begin()),*dptr(dd1->begin()),*diptr(dd2->begin());
9907 for(const int *it=fewModifiedCells->begin();it!=fewModifiedCells->end();it++)
9909 outMesh2DSplit.push_back(BuildRefined2DCell(ret1->getCoords(),mesh2D,*it,dptr+diptr[*it],dptr+diptr[*it+1],intersectEdge1));
9910 ret1->setCoords(outMesh2DSplit.back()->getCoords());
9912 int offset(ret2->getNumberOfTuples());
9913 ret2->pushBackValsSilent(fewModifiedCells->begin(),fewModifiedCells->end());
9914 MCAuto<DataArrayInt> partOfRet3(DataArrayInt::New()); partOfRet3->alloc(2*idsInRet1Colinear->getNumberOfTuples(),1);
9915 partOfRet3->fillWithValue(std::numeric_limits<int>::max()); partOfRet3->rearrange(2);
9916 int kk(0),*ret3ptr(partOfRet3->getPointer());
9917 for(const int *it=idsInDescMesh2DForIdsInRetColinear->begin();it!=idsInDescMesh2DForIdsInRetColinear->end();it++,kk++)
9919 int faceId(std::abs(*it)-1);
9920 for(const int *it2=rdptr+rdiptr[faceId];it2!=rdptr+rdiptr[faceId+1];it2++)
9922 int tmp(fewModifiedCells->findIdFirstEqual(*it2));
9925 if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],-(*it))!=dptr+diptr[*it2+1])
9926 ret3ptr[2*kk]=tmp+offset;
9927 if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],(*it))!=dptr+diptr[*it2+1])
9928 ret3ptr[2*kk+1]=tmp+offset;
9931 {//the current edge is shared by a 2D cell that will be split just after
9932 if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],-(*it))!=dptr+diptr[*it2+1])
9933 ret3ptr[2*kk]=-(*it2+1);
9934 if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],(*it))!=dptr+diptr[*it2+1])
9935 ret3ptr[2*kk+1]=-(*it2+1);
9939 m1Desc->setCoords(ret1->getCoords());
9940 ret1NonCol->setCoords(ret1->getCoords());
9941 ret3->setPartOfValues3(partOfRet3,idsInRet1Colinear->begin(),idsInRet1Colinear->end(),0,2,1,true);
9942 if(!outMesh2DSplit.empty())
9944 DataArrayDouble *da(outMesh2DSplit.back()->getCoords());
9945 for(std::vector< MCAuto<MEDCouplingUMesh> >::iterator itt=outMesh2DSplit.begin();itt!=outMesh2DSplit.end();itt++)
9946 (*itt)->setCoords(da);
9949 cellsToBeModified=cellsToBeModified->buildUniqueNotSorted();
9950 for(const int *it=cellsToBeModified->begin();it!=cellsToBeModified->end();it++)
9952 MCAuto<DataArrayInt> idsNonColPerCell(elts->findIdsEqual(*it));
9953 idsNonColPerCell->transformWithIndArr(eltsIndex3->begin(),eltsIndex3->end());
9954 MCAuto<DataArrayInt> idsNonColPerCell2(idsInRet1NotColinear->selectByTupleId(idsNonColPerCell->begin(),idsNonColPerCell->end()));
9955 MCAuto<MEDCouplingUMesh> partOfMesh1CuttingCur2DCell(static_cast<MEDCouplingUMesh *>(ret1NonCol->buildPartOfMySelf(idsNonColPerCell->begin(),idsNonColPerCell->end())));
9956 MCAuto<DataArrayInt> partOfRet3;
9957 MCAuto<MEDCouplingUMesh> splitOfOneCell(BuildMesh2DCutFrom(eps,*it,m1Desc,partOfMesh1CuttingCur2DCell,dd1->begin()+dd2->getIJ(*it,0),dd1->begin()+dd2->getIJ((*it)+1,0),intersectEdge1,ret2->getNumberOfTuples(),partOfRet3));
9958 ret3->setPartOfValues3(partOfRet3,idsNonColPerCell2->begin(),idsNonColPerCell2->end(),0,2,1,true);
9959 outMesh2DSplit.push_back(splitOfOneCell);
9960 for(int i=0;i<splitOfOneCell->getNumberOfCells();i++)
9961 ret2->pushBackSilent(*it);
9964 std::size_t nbOfMeshes(outMesh2DSplit.size());
9965 std::vector<const MEDCouplingUMesh *> tmp(nbOfMeshes);
9966 for(std::size_t i=0;i<nbOfMeshes;i++)
9967 tmp[i]=outMesh2DSplit[i];
9969 ret1->getCoords()->setInfoOnComponents(compNames);
9970 MCAuto<MEDCouplingUMesh> ret2D(MEDCouplingUMesh::MergeUMeshesOnSameCoords(tmp));
9971 // To finish - filter ret3 - std::numeric_limits<int>::max() -> -1 - negate values must be resolved.
9973 MCAuto<DataArrayInt> edgesToDealWith(ret3->findIdsStricltyNegative());
9974 for(const int *it=edgesToDealWith->begin();it!=edgesToDealWith->end();it++)
9976 int old2DCellId(-ret3->getIJ(*it,0)-1);
9977 MCAuto<DataArrayInt> candidates(ret2->findIdsEqual(old2DCellId));
9978 ret3->setIJ(*it,0,FindRightCandidateAmong(ret2D,candidates->begin(),candidates->end(),ret1,*it%2==0?-((*it)/2+1):(*it)/2+1,eps));// div by 2 because 2 components natively in ret3
9980 ret3->changeValue(std::numeric_limits<int>::max(),-1);
9983 splitMesh1D=ret1.retn();
9984 splitMesh2D=ret2D.retn();
9985 cellIdInMesh2D=ret2.retn();
9986 cellIdInMesh1D=ret3.retn();
9990 * Private. Third step of the partitioning algorithm (Intersect2DMeshes): reconstruct full 2D cells from the
9991 * (newly created) nodes corresponding to the edge intersections.
9993 * @param[out] cr, crI connectivity of the resulting mesh
9994 * @param[out] cNb1, cNb2 correspondance arrays giving for the merged mesh the initial cells IDs in m1 / m2
9995 * TODO: describe input parameters
9997 void MEDCouplingUMesh::BuildIntersecting2DCellsFromEdges(double eps, const MEDCouplingUMesh *m1, const int *desc1, const int *descIndx1,
9998 const std::vector<std::vector<int> >& intesctEdges1, const std::vector< std::vector<int> >& colinear2,
9999 const MEDCouplingUMesh *m2, const int *desc2, const int *descIndx2, const std::vector<std::vector<int> >& intesctEdges2,
10000 const std::vector<double>& addCoords,
10001 std::vector<double>& addCoordsQuadratic, std::vector<int>& cr, std::vector<int>& crI, std::vector<int>& cNb1, std::vector<int>& cNb2)
10003 static const int SPACEDIM=2;
10004 const double *coo1(m1->getCoords()->getConstPointer());
10005 const int *conn1(m1->getNodalConnectivity()->getConstPointer()),*connI1(m1->getNodalConnectivityIndex()->getConstPointer());
10006 int offset1(m1->getNumberOfNodes());
10007 const double *coo2(m2->getCoords()->getConstPointer());
10008 const int *conn2(m2->getNodalConnectivity()->getConstPointer()),*connI2(m2->getNodalConnectivityIndex()->getConstPointer());
10009 int offset2(offset1+m2->getNumberOfNodes());
10010 int offset3(offset2+((int)addCoords.size())/2);
10011 MCAuto<DataArrayDouble> bbox1Arr(m1->getBoundingBoxForBBTree()),bbox2Arr(m2->getBoundingBoxForBBTree());
10012 const double *bbox1(bbox1Arr->begin()),*bbox2(bbox2Arr->begin());
10013 // Here a BBTree on 2D-cells, not on segments:
10014 BBTree<SPACEDIM,int> myTree(bbox2,0,0,m2->getNumberOfCells(),eps);
10015 int ncell1(m1->getNumberOfCells());
10017 for(int i=0;i<ncell1;i++)
10019 std::vector<int> candidates2;
10020 myTree.getIntersectingElems(bbox1+i*2*SPACEDIM,candidates2);
10021 std::map<INTERP_KERNEL::Node *,int> mapp;
10022 std::map<int,INTERP_KERNEL::Node *> mappRev;
10023 INTERP_KERNEL::QuadraticPolygon pol1;
10024 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn1[connI1[i]];
10025 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
10026 // Populate mapp and mappRev with nodes from the current cell (i) from mesh1 - this also builds the Node* objects:
10027 MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,/* output */mapp,mappRev);
10028 // pol1 is the full cell from mesh2, in QP format, with all the additional intersecting nodes.
10029 pol1.buildFromCrudeDataArray(mappRev,cm.isQuadratic(),conn1+connI1[i]+1,coo1,
10030 desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1);
10032 std::set<INTERP_KERNEL::Edge *> edges1;// store all edges of pol1 that are NOT consumed by intersect cells. If any after iteration over candidates2 -> a part of pol1 should appear in result
10033 std::set<INTERP_KERNEL::Edge *> edgesBoundary2;// store all edges that are on boundary of (pol2 intersect pol1) minus edges on pol1.
10034 INTERP_KERNEL::IteratorOnComposedEdge it1(&pol1);
10035 for(it1.first();!it1.finished();it1.next())
10036 edges1.insert(it1.current()->getPtr());
10038 std::map<int,std::vector<INTERP_KERNEL::ElementaryEdge *> > edgesIn2ForShare; // common edges
10039 std::vector<INTERP_KERNEL::QuadraticPolygon> pol2s(candidates2.size());
10041 for(std::vector<int>::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++,ii++)
10043 INTERP_KERNEL::NormalizedCellType typ2=(INTERP_KERNEL::NormalizedCellType)conn2[connI2[*it2]];
10044 const INTERP_KERNEL::CellModel& cm2=INTERP_KERNEL::CellModel::GetCellModel(typ2);
10045 // Complete mapping with elements coming from the current cell it2 in mesh2:
10046 MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,/* output */mapp,mappRev);
10047 // pol2 is the new QP in the final merged result.
10048 pol2s[ii].buildFromCrudeDataArray2(mappRev,cm2.isQuadratic(),conn2+connI2[*it2]+1,coo2,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,
10049 pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2, /* output */ edgesIn2ForShare);
10052 for(std::vector<int>::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++,ii++)
10054 INTERP_KERNEL::ComposedEdge::InitLocationsWithOther(pol1,pol2s[ii]);
10055 pol2s[ii].updateLocOfEdgeFromCrudeDataArray2(desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2);
10056 //MEDCouplingUMeshAssignOnLoc(pol1,pol2,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,colinear2);
10057 pol1.buildPartitionsAbs(pol2s[ii],edges1,edgesBoundary2,mapp,i,*it2,offset3,addCoordsQuadratic,cr,crI,cNb1,cNb2);
10059 // Deals with remaining (non-consumed) edges from m1: these are the edges that were never touched
10060 // by m2 but that we still want to keep in the final result.
10061 if(!edges1.empty())
10065 INTERP_KERNEL::QuadraticPolygon::ComputeResidual(pol1,edges1,edgesBoundary2,mapp,offset3,i,addCoordsQuadratic,cr,crI,cNb1,cNb2);
10067 catch(INTERP_KERNEL::Exception& e)
10069 std::ostringstream oss; oss << "Error when computing residual of cell #" << i << " in source/m1 mesh ! Maybe the neighbours of this cell in mesh are not well connected !\n" << "The deep reason is the following : " << e.what();
10070 throw INTERP_KERNEL::Exception(oss.str().c_str());
10073 for(std::map<int,INTERP_KERNEL::Node *>::const_iterator it=mappRev.begin();it!=mappRev.end();it++)
10074 (*it).second->decrRef();
10079 * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
10080 * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
10081 * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
10082 * The caller is to deal with the resulting DataArrayInt.
10083 * \throw If the coordinate array is not set.
10084 * \throw If the nodal connectivity of the cells is not defined.
10085 * \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
10086 * \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
10088 * \sa DataArrayInt::sortEachPairToMakeALinkedList
10090 DataArrayInt *MEDCouplingUMesh::orderConsecutiveCells1D() const
10092 checkFullyDefined();
10093 if(getMeshDimension()!=1)
10094 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
10096 // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
10097 MCAuto<DataArrayInt> _d(DataArrayInt::New()),_dI(DataArrayInt::New());
10098 MCAuto<DataArrayInt> _rD(DataArrayInt::New()),_rDI(DataArrayInt::New());
10099 MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
10100 const int *d(_d->getConstPointer()), *dI(_dI->getConstPointer());
10101 const int *rD(_rD->getConstPointer()), *rDI(_rDI->getConstPointer());
10102 MCAuto<DataArrayInt> _dsi(_rDI->deltaShiftIndex());
10103 const int * dsi(_dsi->getConstPointer());
10104 MCAuto<DataArrayInt> dsii = _dsi->findIdsNotInRange(0,3);
10106 if (dsii->getNumberOfTuples())
10107 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
10109 int nc(getNumberOfCells());
10110 MCAuto<DataArrayInt> result(DataArrayInt::New());
10111 result->alloc(nc,1);
10113 // set of edges not used so far
10114 std::set<int> edgeSet;
10115 for (int i=0; i<nc; edgeSet.insert(i), i++);
10119 // while we have points with only one neighbor segments
10122 std::list<int> linePiece;
10123 // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
10124 for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
10126 // Fill the list forward (resp. backward) from the start segment:
10127 int activeSeg = startSeg;
10128 int prevPointId = -20;
10130 while (!edgeSet.empty())
10132 if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
10135 linePiece.push_back(activeSeg);
10137 linePiece.push_front(activeSeg);
10138 edgeSet.erase(activeSeg);
10141 int ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
10142 ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
10143 if (dsi[ptId] == 1) // hitting the end of the line
10145 prevPointId = ptId;
10146 int seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
10147 activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
10150 // Done, save final piece into DA:
10151 std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
10152 newIdx += linePiece.size();
10154 // identify next valid start segment (one which is not consumed)
10155 if(!edgeSet.empty())
10156 startSeg = *(edgeSet.begin());
10158 while (!edgeSet.empty());
10159 return result.retn();
10164 void IKGeo2DInternalMapper2(INTERP_KERNEL::Node *n, const std::map<MCAuto<INTERP_KERNEL::Node>,int>& m, int forbVal0, int forbVal1, std::vector<int>& isect)
10166 MCAuto<INTERP_KERNEL::Node> nTmp(n); nTmp->incrRef();
10167 std::map<MCAuto<INTERP_KERNEL::Node>,int>::const_iterator it(m.find(nTmp));
10169 throw INTERP_KERNEL::Exception("Internal error in remapping !");
10170 int v((*it).second);
10171 if(v==forbVal0 || v==forbVal1)
10173 if(std::find(isect.begin(),isect.end(),v)==isect.end())
10174 isect.push_back(v);
10177 bool IKGeo2DInternalMapper(const INTERP_KERNEL::ComposedEdge& c, const std::map<MCAuto<INTERP_KERNEL::Node>,int>& m, int forbVal0, int forbVal1, std::vector<int>& isect)
10182 bool presenceOfOn(false);
10183 for(int i=0;i<sz;i++)
10185 INTERP_KERNEL::ElementaryEdge *e(c[i]);
10186 if(e->getLoc()!=INTERP_KERNEL::FULL_ON_1)
10188 IKGeo2DInternalMapper2(e->getStartNode(),m,forbVal0,forbVal1,isect);
10189 IKGeo2DInternalMapper2(e->getEndNode(),m,forbVal0,forbVal1,isect);
10191 return presenceOfOn;
10197 * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
10198 * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
10199 * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
10200 * a minimal creation of new nodes is wanted.
10201 * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
10202 * nodes if a SEG3 is split without information of middle.
10203 * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
10204 * avoid to have a non conform mesh.
10206 * \return int - the number of new nodes created (in most of cases 0).
10208 * \throw If \a this is not coherent.
10209 * \throw If \a this has not spaceDim equal to 2.
10210 * \throw If \a this has not meshDim equal to 2.
10211 * \throw If some subcells needed to be split are orphan.
10212 * \sa MEDCouplingUMesh::conformize2D
10214 int MEDCouplingUMesh::split2DCells(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *midOpt, const DataArrayInt *midOptI)
10216 if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
10217 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
10218 desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
10219 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10220 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10221 if(midOpt==0 && midOptI==0)
10223 split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
10226 else if(midOpt!=0 && midOptI!=0)
10227 return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
10229 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
10233 * \b WARNING this method is \b potentially \b non \b const (if returned array is empty).
10234 * \b WARNING this method lead to have a non geometric type sorted mesh (for MED file users) !
10235 * This method performs a conformization of \b this. So if a edge in \a this can be split into entire edges in \a this this method
10236 * will suppress such edges to use sub edges in \a this. So this method does not add nodes in \a this if merged edges are both linear (INTERP_KERNEL::NORM_SEG2).
10237 * In the other cases new nodes can be created. If any are created, they will be appended at the end of the coordinates object before the invokation of this method.
10239 * Whatever the returned value, this method does not alter the order of cells in \a this neither the orientation of cells.
10240 * The modified cells, if any, are systematically declared as NORM_POLYGON or NORM_QPOLYG depending on the initial quadraticness of geometric type.
10242 * This method expects that \b this has a meshDim equal 2 and spaceDim equal to 2 too.
10243 * This method expects that all nodes in \a this are not closer than \a eps.
10244 * If it is not the case you can invoke MEDCouplingUMesh::mergeNodes before calling this method.
10246 * \param [in] eps the relative error to detect merged edges.
10247 * \return DataArrayInt * - The list of cellIds in \a this that have been subdivided. If empty, nothing changed in \a this (as if it were a const method). The array is a newly allocated array
10248 * that the user is expected to deal with.
10250 * \throw If \a this is not coherent.
10251 * \throw If \a this has not spaceDim equal to 2.
10252 * \throw If \a this has not meshDim equal to 2.
10253 * \sa MEDCouplingUMesh::mergeNodes, MEDCouplingUMesh::split2DCells
10255 DataArrayInt *MEDCouplingUMesh::conformize2D(double eps)
10257 static const int SPACEDIM=2;
10258 checkConsistencyLight();
10259 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10260 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::conformize2D : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10261 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
10262 MCAuto<MEDCouplingUMesh> mDesc(buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));
10263 const int *c(mDesc->getNodalConnectivity()->getConstPointer()),*ci(mDesc->getNodalConnectivityIndex()->getConstPointer()),*rd(revDesc1->getConstPointer()),*rdi(revDescIndx1->getConstPointer());
10264 MCAuto<DataArrayDouble> bboxArr(mDesc->getBoundingBoxForBBTree());
10265 const double *bbox(bboxArr->begin()),*coords(getCoords()->begin());
10266 int nCell(getNumberOfCells()),nDescCell(mDesc->getNumberOfCells());
10267 std::vector< std::vector<int> > intersectEdge(nDescCell),overlapEdge(nDescCell);
10268 std::vector<double> addCoo;
10269 BBTree<SPACEDIM,int> myTree(bbox,0,0,nDescCell,-eps);
10270 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10271 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10272 for(int i=0;i<nDescCell;i++)
10274 std::vector<int> candidates;
10275 myTree.getIntersectingElems(bbox+i*2*SPACEDIM,candidates);
10276 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
10279 std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
10280 INTERP_KERNEL::Edge *e1(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coords,m)),
10281 *e2(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[*it]],c+ci[*it]+1,coords,m));
10282 INTERP_KERNEL::MergePoints merge;
10283 INTERP_KERNEL::QuadraticPolygon c1,c2;
10284 e1->intersectWith(e2,merge,c1,c2);
10285 e1->decrRef(); e2->decrRef();
10286 if(IKGeo2DInternalMapper(c1,m,c[ci[i]+1],c[ci[i]+2],intersectEdge[i]))
10287 overlapEdge[i].push_back(*it);
10288 if(IKGeo2DInternalMapper(c2,m,c[ci[*it]+1],c[ci[*it]+2],intersectEdge[*it]))
10289 overlapEdge[*it].push_back(i);
10292 // splitting done. sort intersect point in intersectEdge.
10293 std::vector< std::vector<int> > middle(nDescCell);
10294 int nbOf2DCellsToBeSplit(0);
10295 bool middleNeedsToBeUsed(false);
10296 std::vector<bool> cells2DToTreat(nDescCell,false);
10297 for(int i=0;i<nDescCell;i++)
10299 std::vector<int>& isect(intersectEdge[i]);
10300 int sz((int)isect.size());
10303 std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
10304 INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coords,m));
10305 e->sortSubNodesAbs(coords,isect);
10310 int idx0(rdi[i]),idx1(rdi[i+1]);
10312 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::conformize2D : internal error #0 !");
10313 if(!cells2DToTreat[rd[idx0]])
10315 cells2DToTreat[rd[idx0]]=true;
10316 nbOf2DCellsToBeSplit++;
10318 // try to reuse at most eventual 'middle' of SEG3
10319 std::vector<int>& mid(middle[i]);
10320 mid.resize(sz+1,-1);
10321 if((INTERP_KERNEL::NormalizedCellType)c[ci[i]]==INTERP_KERNEL::NORM_SEG3)
10323 middleNeedsToBeUsed=true;
10324 const std::vector<int>& candidates(overlapEdge[i]);
10325 std::vector<int> trueCandidates;
10326 for(std::vector<int>::const_iterator itc=candidates.begin();itc!=candidates.end();itc++)
10327 if((INTERP_KERNEL::NormalizedCellType)c[ci[*itc]]==INTERP_KERNEL::NORM_SEG3)
10328 trueCandidates.push_back(*itc);
10329 int stNode(c[ci[i]+1]),endNode(isect[0]);
10330 for(int j=0;j<sz+1;j++)
10332 for(std::vector<int>::const_iterator itc=trueCandidates.begin();itc!=trueCandidates.end();itc++)
10334 int tmpSt(c[ci[*itc]+1]),tmpEnd(c[ci[*itc]+2]);
10335 if((tmpSt==stNode && tmpEnd==endNode) || (tmpSt==endNode && tmpEnd==stNode))
10336 { mid[j]=*itc; break; }
10339 endNode=j<sz-1?isect[j+1]:c[ci[i]+2];
10344 MCAuto<DataArrayInt> ret(DataArrayInt::New()),notRet(DataArrayInt::New()); ret->alloc(nbOf2DCellsToBeSplit,1);
10345 if(nbOf2DCellsToBeSplit==0)
10348 int *retPtr(ret->getPointer());
10349 for(int i=0;i<nCell;i++)
10350 if(cells2DToTreat[i])
10353 MCAuto<DataArrayInt> mSafe,nSafe,oSafe,pSafe,qSafe,rSafe;
10354 DataArrayInt *m(0),*n(0),*o(0),*p(0),*q(0),*r(0);
10355 MEDCouplingUMesh::ExtractFromIndexedArrays(ret->begin(),ret->end(),desc1,descIndx1,m,n); mSafe=m; nSafe=n;
10356 DataArrayInt::PutIntoToSkylineFrmt(intersectEdge,o,p); oSafe=o; pSafe=p;
10357 if(middleNeedsToBeUsed)
10358 { DataArrayInt::PutIntoToSkylineFrmt(middle,q,r); qSafe=q; rSafe=r; }
10359 MCAuto<MEDCouplingUMesh> modif(static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(ret->begin(),ret->end(),true)));
10360 int nbOfNodesCreated(modif->split2DCells(mSafe,nSafe,oSafe,pSafe,qSafe,rSafe));
10361 setCoords(modif->getCoords());//if nbOfNodesCreated==0 modif and this have the same coordinates pointer so this line has no effect. But for quadratic cases this line is important.
10362 setPartOfMySelf(ret->begin(),ret->end(),*modif);
10364 bool areNodesMerged; int newNbOfNodes;
10365 if(nbOfNodesCreated!=0)
10366 MCAuto<DataArrayInt> tmp(mergeNodes(eps,areNodesMerged,newNbOfNodes));
10372 * This non const method works on 2D mesh. This method scans every cell in \a this and look if each edge constituting this cell is not mergeable with neighbors edges of that cell.
10373 * If yes, the cell is "repaired" to minimize at most its number of edges. So this method do not change the overall shape of cells in \a this (with eps precision).
10374 * This method do not take care of shared edges between cells, so this method can lead to a non conform mesh (\a this). If a conform mesh is required you're expected
10375 * to invoke MEDCouplingUMesh::mergeNodes and MEDCouplingUMesh::conformize2D right after this call.
10376 * This method works on any 2D geometric types of cell (even static one). If a cell is touched its type becomes dynamic automaticaly. For 2D "repaired" quadratic cells
10377 * new nodes for center of merged edges is are systematically created and appended at the end of the previously existing nodes.
10379 * If the returned array is empty it means that nothing has changed in \a this (as if it were a const method). If the array is not empty the connectivity of \a this is modified
10380 * using new instance, idem for coordinates.
10382 * If \a this is constituted by only linear 2D cells, this method is close to the computation of the convex hull of each cells in \a this.
10384 * \return DataArrayInt * - The list of cellIds in \a this that have at least one edge colinearized.
10386 * \throw If \a this is not coherent.
10387 * \throw If \a this has not spaceDim equal to 2.
10388 * \throw If \a this has not meshDim equal to 2.
10390 * \sa MEDCouplingUMesh::conformize2D, MEDCouplingUMesh::mergeNodes, MEDCouplingUMesh::convexEnvelop2D.
10392 DataArrayInt *MEDCouplingUMesh::colinearize2D(double eps)
10394 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
10395 checkConsistencyLight();
10396 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10397 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::colinearize2D : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10398 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10399 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10400 int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
10401 const int *cptr(_nodal_connec->begin()),*ciptr(_nodal_connec_index->begin());
10402 MCAuto<DataArrayInt> newc(DataArrayInt::New()),newci(DataArrayInt::New()); newci->alloc(nbOfCells+1,1); newc->alloc(0,1); newci->setIJ(0,0,0);
10403 MCAuto<DataArrayDouble> appendedCoords(DataArrayDouble::New()); appendedCoords->alloc(0,1);//1 not 2 it is not a bug.
10404 const double *coords(_coords->begin());
10405 int *newciptr(newci->getPointer());
10406 for(int i=0;i<nbOfCells;i++,newciptr++,ciptr++)
10408 if(Colinearize2DCell(coords,cptr+ciptr[0],cptr+ciptr[1],nbOfNodes,newc,appendedCoords))
10409 ret->pushBackSilent(i);
10410 newciptr[1]=newc->getNumberOfTuples();
10415 if(!appendedCoords->empty())
10417 appendedCoords->rearrange(2);
10418 MCAuto<DataArrayDouble> newCoords(DataArrayDouble::Aggregate(getCoords(),appendedCoords));//treat info on components
10420 setCoords(newCoords);
10423 setConnectivity(newc,newci,true);
10428 * \param [out] intersectEdge1 - for each cell in \a m1Desc returns the result of the split. The result is given using pair of int given resp start and stop.
10429 * So for all edge \a i in \a m1Desc \a intersectEdge1[i] is of length 2*n where n is the number of sub edges.
10430 * And for each j in [1,n) intersect[i][2*(j-1)+1]==intersect[i][2*j].
10431 * \param [out] subDiv2 - for each cell in \a m2Desc returns nodes that split it using convention \a m1Desc first, then \a m2Desc, then addCoo
10432 * \param [out] colinear2 - for each cell in \a m2Desc returns the edges in \a m1Desc that are colinear to it.
10433 * \param [out] addCoo - nodes to be append at the end
10434 * \param [out] mergedNodes - gives all pair of nodes of \a m2Desc that have same location than some nodes in \a m1Desc. key is id in \a m2Desc offseted and value is id in \a m1Desc.
10436 void MEDCouplingUMesh::Intersect1DMeshes(const MEDCouplingUMesh *m1Desc, const MEDCouplingUMesh *m2Desc, double eps,
10437 std::vector< std::vector<int> >& intersectEdge1, std::vector< std::vector<int> >& colinear2, std::vector< std::vector<int> >& subDiv2, std::vector<double>& addCoo, std::map<int,int>& mergedNodes)
10439 static const int SPACEDIM=2;
10440 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10441 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10442 const int *c1(m1Desc->getNodalConnectivity()->getConstPointer()),*ci1(m1Desc->getNodalConnectivityIndex()->getConstPointer());
10443 // Build BB tree of all edges in the tool mesh (second mesh)
10444 MCAuto<DataArrayDouble> bbox1Arr(m1Desc->getBoundingBoxForBBTree()),bbox2Arr(m2Desc->getBoundingBoxForBBTree());
10445 const double *bbox1(bbox1Arr->begin()),*bbox2(bbox2Arr->begin());
10446 int nDescCell1(m1Desc->getNumberOfCells()),nDescCell2(m2Desc->getNumberOfCells());
10447 intersectEdge1.resize(nDescCell1);
10448 colinear2.resize(nDescCell2);
10449 subDiv2.resize(nDescCell2);
10450 BBTree<SPACEDIM,int> myTree(bbox2,0,0,m2Desc->getNumberOfCells(),-eps);
10452 std::vector<int> candidates1(1);
10453 int offset1(m1Desc->getNumberOfNodes());
10454 int offset2(offset1+m2Desc->getNumberOfNodes());
10455 for(int i=0;i<nDescCell1;i++) // for all edges in the first mesh
10457 std::vector<int> candidates2; // edges of mesh2 candidate for intersection
10458 myTree.getIntersectingElems(bbox1+i*2*SPACEDIM,candidates2);
10459 if(!candidates2.empty()) // candidates2 holds edges from the second mesh potentially intersecting current edge i in mesh1
10461 std::map<INTERP_KERNEL::Node *,int> map1,map2;
10462 // pol2 is not necessarily a closed polygon: just a set of (quadratic) edges (same as candidates2) in the Geometric DS format
10463 INTERP_KERNEL::QuadraticPolygon *pol2=MEDCouplingUMeshBuildQPFromMesh(m2Desc,candidates2,map2);
10465 INTERP_KERNEL::QuadraticPolygon *pol1=MEDCouplingUMeshBuildQPFromMesh(m1Desc,candidates1,map1);
10466 // This following part is to avoid that some removed nodes (for example due to a merge between pol1 and pol2) are replaced by a newly created one
10467 // This trick guarantees that Node * are discriminant (i.e. form a unique identifier)
10468 std::set<INTERP_KERNEL::Node *> nodes;
10469 pol1->getAllNodes(nodes); pol2->getAllNodes(nodes);
10470 std::size_t szz(nodes.size());
10471 std::vector< MCAuto<INTERP_KERNEL::Node> > nodesSafe(szz);
10472 std::set<INTERP_KERNEL::Node *>::const_iterator itt(nodes.begin());
10473 for(std::size_t iii=0;iii<szz;iii++,itt++)
10474 { (*itt)->incrRef(); nodesSafe[iii]=*itt; }
10475 // end of protection
10476 // Performs egde cutting:
10477 pol1->splitAbs(*pol2,map1,map2,offset1,offset2,candidates2,intersectEdge1[i],i,colinear2,subDiv2,addCoo,mergedNodes);
10482 // Copy the edge (take only the two first points, ie discard quadratic point at this stage)
10483 intersectEdge1[i].insert(intersectEdge1[i].end(),c1+ci1[i]+1,c1+ci1[i]+3);
10488 * This method is private and is the first step of Partition of 2D mesh (spaceDim==2 and meshDim==2).
10489 * It builds the descending connectivity of the two meshes, and then using a binary tree
10490 * it computes the edge intersections. This results in new points being created : they're stored in addCoo.
10491 * Documentation about parameters colinear2 and subDiv2 can be found in method QuadraticPolygon::splitAbs().
10493 void MEDCouplingUMesh::IntersectDescending2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2, double eps,
10494 std::vector< std::vector<int> >& intersectEdge1, std::vector< std::vector<int> >& colinear2, std::vector< std::vector<int> >& subDiv2,
10495 MEDCouplingUMesh *& m1Desc, DataArrayInt *&desc1, DataArrayInt *&descIndx1, DataArrayInt *&revDesc1, DataArrayInt *&revDescIndx1,
10496 std::vector<double>& addCoo,
10497 MEDCouplingUMesh *& m2Desc, DataArrayInt *&desc2, DataArrayInt *&descIndx2, DataArrayInt *&revDesc2, DataArrayInt *&revDescIndx2)
10499 // Build desc connectivity
10500 desc1=DataArrayInt::New(); descIndx1=DataArrayInt::New(); revDesc1=DataArrayInt::New(); revDescIndx1=DataArrayInt::New();
10501 desc2=DataArrayInt::New();
10502 descIndx2=DataArrayInt::New();
10503 revDesc2=DataArrayInt::New();
10504 revDescIndx2=DataArrayInt::New();
10505 MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(revDesc1),dd4(revDescIndx1);
10506 MCAuto<DataArrayInt> dd5(desc2),dd6(descIndx2),dd7(revDesc2),dd8(revDescIndx2);
10507 m1Desc=m1->buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1);
10508 m2Desc=m2->buildDescendingConnectivity2(desc2,descIndx2,revDesc2,revDescIndx2);
10509 MCAuto<MEDCouplingUMesh> dd9(m1Desc),dd10(m2Desc);
10510 std::map<int,int> notUsedMap;
10511 Intersect1DMeshes(m1Desc,m2Desc,eps,intersectEdge1,colinear2,subDiv2,addCoo,notUsedMap);
10512 m1Desc->incrRef(); desc1->incrRef(); descIndx1->incrRef(); revDesc1->incrRef(); revDescIndx1->incrRef();
10513 m2Desc->incrRef(); desc2->incrRef(); descIndx2->incrRef(); revDesc2->incrRef(); revDescIndx2->incrRef();
10517 * This method performs the 2nd step of Partition of 2D mesh.
10518 * This method has 4 inputs :
10519 * - a mesh 'm1' with meshDim==1 and a SpaceDim==2
10520 * - a mesh 'm2' with meshDim==1 and a SpaceDim==2
10521 * - subDiv of size 'm2->getNumberOfCells()' that lists for each seg cell in 'm' the splitting node ids randomly sorted.
10522 * The aim of this method is to sort the splitting nodes, if any, and to put them in 'intersectEdge' output parameter based on edges of mesh 'm2'
10523 * Nodes end up lying consecutively on a cutted edge.
10524 * \param m1 is expected to be a mesh of meshDimension equal to 1 and spaceDim equal to 2. No check of that is performed by this method.
10525 * (Only present for its coords in case of 'subDiv' shares some nodes of 'm1')
10526 * \param m2 is expected to be a mesh of meshDimension equal to 1 and spaceDim equal to 2. No check of that is performed by this method.
10527 * \param addCoo input parameter with additional nodes linked to intersection of the 2 meshes.
10528 * \param[out] intersectEdge the same content as subDiv, but correclty oriented.
10530 void MEDCouplingUMesh::BuildIntersectEdges(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2,
10531 const std::vector<double>& addCoo,
10532 const std::vector< std::vector<int> >& subDiv, std::vector< std::vector<int> >& intersectEdge)
10534 int offset1=m1->getNumberOfNodes();
10535 int ncell=m2->getNumberOfCells();
10536 const int *c=m2->getNodalConnectivity()->getConstPointer();
10537 const int *cI=m2->getNodalConnectivityIndex()->getConstPointer();
10538 const double *coo=m2->getCoords()->getConstPointer();
10539 const double *cooBis=m1->getCoords()->getConstPointer();
10540 int offset2=offset1+m2->getNumberOfNodes();
10541 intersectEdge.resize(ncell);
10542 for(int i=0;i<ncell;i++,cI++)
10544 const std::vector<int>& divs=subDiv[i];
10545 int nnode=cI[1]-cI[0]-1;
10546 std::map<int, std::pair<INTERP_KERNEL::Node *,bool> > mapp2;
10547 std::map<INTERP_KERNEL::Node *, int> mapp22;
10548 for(int j=0;j<nnode;j++)
10550 INTERP_KERNEL::Node *nn=new INTERP_KERNEL::Node(coo[2*c[(*cI)+j+1]],coo[2*c[(*cI)+j+1]+1]);
10551 int nnid=c[(*cI)+j+1];
10552 mapp2[nnid]=std::pair<INTERP_KERNEL::Node *,bool>(nn,true);
10553 mapp22[nn]=nnid+offset1;
10555 INTERP_KERNEL::Edge *e=MEDCouplingUMeshBuildQPFromEdge((INTERP_KERNEL::NormalizedCellType)c[*cI],mapp2,c+(*cI)+1);
10556 for(std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >::const_iterator it=mapp2.begin();it!=mapp2.end();it++)
10557 ((*it).second.first)->decrRef();
10558 std::vector<INTERP_KERNEL::Node *> addNodes(divs.size());
10559 std::map<INTERP_KERNEL::Node *,int> mapp3;
10560 for(std::size_t j=0;j<divs.size();j++)
10563 INTERP_KERNEL::Node *tmp=0;
10565 tmp=new INTERP_KERNEL::Node(cooBis[2*id],cooBis[2*id+1]);
10566 else if(id<offset2)
10567 tmp=new INTERP_KERNEL::Node(coo[2*(id-offset1)],coo[2*(id-offset1)+1]);//if it happens, bad news mesh 'm2' is non conform.
10569 tmp=new INTERP_KERNEL::Node(addCoo[2*(id-offset2)],addCoo[2*(id-offset2)+1]);
10573 e->sortIdsAbs(addNodes,mapp22,mapp3,intersectEdge[i]);
10574 for(std::vector<INTERP_KERNEL::Node *>::const_iterator it=addNodes.begin();it!=addNodes.end();it++)
10581 * This method is part of the Slice3D algorithm. It is the first step of assembly process, ones coordinates have been computed (by MEDCouplingUMesh::split3DCurveWithPlane method).
10582 * This method allows to compute given the status of 3D curve cells and the descending connectivity 3DSurf->3DCurve to deduce the intersection of each 3D surf cells
10583 * with a plane. The result will be put in 'cut3DSuf' out parameter.
10584 * \param [in] cut3DCurve input paramter that gives for each 3DCurve cell if it owns fully to the plane or partially.
10585 * \param [out] nodesOnPlane, returns all the nodes that are on the plane.
10586 * \param [in] nodal3DSurf is the nodal connectivity of 3D surf mesh.
10587 * \param [in] nodalIndx3DSurf is the nodal connectivity index of 3D surf mesh.
10588 * \param [in] nodal3DCurve is the nodal connectivity of 3D curve mesh.
10589 * \param [in] nodal3DIndxCurve is the nodal connectivity index of 3D curve mesh.
10590 * \param [in] desc is the descending connectivity 3DSurf->3DCurve
10591 * \param [in] descIndx is the descending connectivity index 3DSurf->3DCurve
10592 * \param [out] cut3DSuf input/output param.
10594 void MEDCouplingUMesh::AssemblyForSplitFrom3DCurve(const std::vector<int>& cut3DCurve, std::vector<int>& nodesOnPlane, const int *nodal3DSurf, const int *nodalIndx3DSurf,
10595 const int *nodal3DCurve, const int *nodalIndx3DCurve,
10596 const int *desc, const int *descIndx,
10597 std::vector< std::pair<int,int> >& cut3DSurf)
10599 std::set<int> nodesOnP(nodesOnPlane.begin(),nodesOnPlane.end());
10600 int nbOf3DSurfCell=(int)cut3DSurf.size();
10601 for(int i=0;i<nbOf3DSurfCell;i++)
10603 std::vector<int> res;
10604 int offset=descIndx[i];
10605 int nbOfSeg=descIndx[i+1]-offset;
10606 for(int j=0;j<nbOfSeg;j++)
10608 int edgeId=desc[offset+j];
10609 int status=cut3DCurve[edgeId];
10613 res.push_back(status);
10616 res.push_back(nodal3DCurve[nodalIndx3DCurve[edgeId]+1]);
10617 res.push_back(nodal3DCurve[nodalIndx3DCurve[edgeId]+2]);
10625 cut3DSurf[i].first=res[0]; cut3DSurf[i].second=res[1];
10631 std::set<int> s1(nodal3DSurf+nodalIndx3DSurf[i]+1,nodal3DSurf+nodalIndx3DSurf[i+1]);
10632 std::set_intersection(nodesOnP.begin(),nodesOnP.end(),s1.begin(),s1.end(),std::back_insert_iterator< std::vector<int> >(res));
10635 cut3DSurf[i].first=res[0]; cut3DSurf[i].second=res[1];
10639 cut3DSurf[i].first=-1; cut3DSurf[i].second=-1;
10644 {// case when plane is on a multi colinear edge of a polyhedron
10645 if((int)res.size()==2*nbOfSeg)
10647 cut3DSurf[i].first=-2; cut3DSurf[i].second=i;
10650 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AssemblyPointsFrom3DCurve : unexpected situation !");
10657 * \a this is expected to be a mesh with spaceDim==3 and meshDim==3. If not an exception will be thrown.
10658 * This method is part of the Slice3D algorithm. It is the second step of assembly process, ones coordinates have been computed (by MEDCouplingUMesh::split3DCurveWithPlane method).
10659 * This method allows to compute given the result of 3D surf cells with plane and the descending connectivity 3D->3DSurf to deduce the intersection of each 3D cells
10660 * with a plane. The result will be put in 'nodalRes' 'nodalResIndx' and 'cellIds' out parameters.
10661 * \param cut3DSurf input paramter that gives for each 3DSurf its intersection with plane (result of MEDCouplingUMesh::AssemblyForSplitFrom3DCurve).
10662 * \param desc is the descending connectivity 3D->3DSurf
10663 * \param descIndx is the descending connectivity index 3D->3DSurf
10665 void MEDCouplingUMesh::assemblyForSplitFrom3DSurf(const std::vector< std::pair<int,int> >& cut3DSurf,
10666 const int *desc, const int *descIndx,
10667 DataArrayInt *nodalRes, DataArrayInt *nodalResIndx, DataArrayInt *cellIds) const
10669 checkFullyDefined();
10670 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
10671 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::assemblyForSplitFrom3DSurf works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
10672 const int *nodal3D=_nodal_connec->getConstPointer();
10673 const int *nodalIndx3D=_nodal_connec_index->getConstPointer();
10674 int nbOfCells=getNumberOfCells();
10675 for(int i=0;i<nbOfCells;i++)
10677 std::map<int, std::set<int> > m;
10678 int offset=descIndx[i];
10679 int nbOfFaces=descIndx[i+1]-offset;
10682 for(int j=0;j<nbOfFaces;j++)
10684 const std::pair<int,int>& p=cut3DSurf[desc[offset+j]];
10685 if(p.first!=-1 && p.second!=-1)
10689 start=p.first; end=p.second;
10690 m[p.first].insert(p.second);
10691 m[p.second].insert(p.first);
10695 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodal3D[nodalIndx3D[i]]);
10696 int sz=nodalIndx3D[i+1]-nodalIndx3D[i]-1;
10697 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
10698 INTERP_KERNEL::NormalizedCellType cmsId;
10699 unsigned nbOfNodesSon=cm.fillSonCellNodalConnectivity2(j,nodal3D+nodalIndx3D[i]+1,sz,tmp,cmsId);
10700 start=tmp[0]; end=tmp[nbOfNodesSon-1];
10701 for(unsigned k=0;k<nbOfNodesSon;k++)
10703 m[tmp[k]].insert(tmp[(k+1)%nbOfNodesSon]);
10704 m[tmp[(k+1)%nbOfNodesSon]].insert(tmp[k]);
10711 std::vector<int> conn(1,(int)INTERP_KERNEL::NORM_POLYGON);
10715 std::map<int, std::set<int> >::const_iterator it=m.find(start);
10716 const std::set<int>& s=(*it).second;
10717 std::set<int> s2; s2.insert(prev);
10719 std::set_difference(s.begin(),s.end(),s2.begin(),s2.end(),inserter(s3,s3.begin()));
10722 int val=*s3.begin();
10723 conn.push_back(start);
10730 conn.push_back(end);
10733 nodalRes->insertAtTheEnd(conn.begin(),conn.end());
10734 nodalResIndx->pushBackSilent(nodalRes->getNumberOfTuples());
10735 cellIds->pushBackSilent(i);
10741 * 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
10742 * 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
10743 * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
10744 * 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
10745 * 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.
10747 * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
10749 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const int *nodalConnBg, const int *nodalConnEnd, DataArrayInt *nodalConnecOut)
10751 std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
10754 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
10755 if(cm.getDimension()==2)
10757 const int *node=nodalConnBg+1;
10758 int startNode=*node++;
10759 double refX=coords[2*startNode];
10760 for(;node!=nodalConnEnd;node++)
10762 if(coords[2*(*node)]<refX)
10765 refX=coords[2*startNode];
10768 std::vector<int> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
10772 double angle0=-M_PI/2;
10777 double angleNext=0.;
10778 while(nextNode!=startNode)
10782 for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
10784 if(*node!=tmpOut.back() && *node!=prevNode)
10786 tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
10787 double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
10792 res=angle0-angleM+2.*M_PI;
10801 if(nextNode!=startNode)
10803 angle0=angleNext-M_PI;
10806 prevNode=tmpOut.back();
10807 tmpOut.push_back(nextNode);
10810 std::vector<int> tmp3(2*(sz-1));
10811 std::vector<int>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
10812 std::copy(nodalConnBg+1,nodalConnEnd,it);
10813 if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
10815 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
10818 if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
10820 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
10825 nodalConnecOut->pushBackSilent((int)INTERP_KERNEL::NORM_POLYGON);
10826 nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
10831 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
10834 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
10838 * This method works on an input pair (\b arr, \b arrIndx) where \b arr indexes is in \b arrIndx.
10839 * This method will not impact the size of inout parameter \b arrIndx but the size of \b arr will be modified in case of suppression.
10841 * \param [in] idsToRemoveBg begin of set of ids to remove in \b arr (included)
10842 * \param [in] idsToRemoveEnd end of set of ids to remove in \b arr (excluded)
10843 * \param [in,out] arr array in which the remove operation will be done.
10844 * \param [in,out] arrIndx array in the remove operation will modify
10845 * \param [in] offsetForRemoval (by default 0) offset so that for each i in [0,arrIndx->getNumberOfTuples()-1) removal process will be performed in the following range [arr+arrIndx[i]+offsetForRemoval,arr+arr[i+1])
10846 * \return true if \b arr and \b arrIndx have been modified, false if not.
10848 bool MEDCouplingUMesh::RemoveIdsFromIndexedArrays(const int *idsToRemoveBg, const int *idsToRemoveEnd, DataArrayInt *arr, DataArrayInt *arrIndx, int offsetForRemoval)
10850 if(!arrIndx || !arr)
10851 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : some input arrays are empty !");
10852 if(offsetForRemoval<0)
10853 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : offsetForRemoval should be >=0 !");
10854 std::set<int> s(idsToRemoveBg,idsToRemoveEnd);
10855 int nbOfGrps=arrIndx->getNumberOfTuples()-1;
10856 int *arrIPtr=arrIndx->getPointer();
10858 int previousArrI=0;
10859 const int *arrPtr=arr->getConstPointer();
10860 std::vector<int> arrOut;//no utility to switch to DataArrayInt because copy always needed
10861 for(int i=0;i<nbOfGrps;i++,arrIPtr++)
10863 if(*arrIPtr-previousArrI>offsetForRemoval)
10865 for(const int *work=arrPtr+previousArrI+offsetForRemoval;work!=arrPtr+*arrIPtr;work++)
10867 if(s.find(*work)==s.end())
10868 arrOut.push_back(*work);
10871 previousArrI=*arrIPtr;
10872 *arrIPtr=(int)arrOut.size();
10874 if(arr->getNumberOfTuples()==(int)arrOut.size())
10876 arr->alloc((int)arrOut.size(),1);
10877 std::copy(arrOut.begin(),arrOut.end(),arr->getPointer());
10882 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
10883 * (\ref numbering-indirect).
10884 * This method returns the result of the extraction ( specified by a set of ids in [\b idsOfSelectBg , \b idsOfSelectEnd ) ).
10885 * The selection of extraction is done standardly in new2old format.
10886 * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
10888 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
10889 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
10890 * \param [in] arrIn arr origin array from which the extraction will be done.
10891 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
10892 * \param [out] arrOut the resulting array
10893 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
10894 * \sa MEDCouplingUMesh::ExtractFromIndexedArraysSlice
10896 void MEDCouplingUMesh::ExtractFromIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
10897 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
10899 if(!arrIn || !arrIndxIn)
10900 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input pointer is NULL !");
10901 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
10902 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
10903 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input arrays must have exactly one component !");
10904 std::size_t sz=std::distance(idsOfSelectBg,idsOfSelectEnd);
10905 const int *arrInPtr=arrIn->getConstPointer();
10906 const int *arrIndxPtr=arrIndxIn->getConstPointer();
10907 int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
10909 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
10910 int maxSizeOfArr=arrIn->getNumberOfTuples();
10911 MCAuto<DataArrayInt> arro=DataArrayInt::New();
10912 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
10913 arrIo->alloc((int)(sz+1),1);
10914 const int *idsIt=idsOfSelectBg;
10915 int *work=arrIo->getPointer();
10918 for(std::size_t i=0;i<sz;i++,work++,idsIt++)
10920 if(*idsIt>=0 && *idsIt<nbOfGrps)
10921 lgth+=arrIndxPtr[*idsIt+1]-arrIndxPtr[*idsIt];
10924 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " ! Must be in [0," << nbOfGrps << ") !";
10925 throw INTERP_KERNEL::Exception(oss.str().c_str());
10931 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " and at this pos arrIndxIn[" << *idsIt;
10932 oss << "+1]-arrIndxIn[" << *idsIt << "] < 0 ! The input index array is bugged !";
10933 throw INTERP_KERNEL::Exception(oss.str().c_str());
10936 arro->alloc(lgth,1);
10937 work=arro->getPointer();
10938 idsIt=idsOfSelectBg;
10939 for(std::size_t i=0;i<sz;i++,idsIt++)
10941 if(arrIndxPtr[*idsIt]>=0 && arrIndxPtr[*idsIt+1]<=maxSizeOfArr)
10942 work=std::copy(arrInPtr+arrIndxPtr[*idsIt],arrInPtr+arrIndxPtr[*idsIt+1],work);
10945 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " arrIndx[" << *idsIt << "] must be >= 0 and arrIndx[";
10946 oss << *idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
10947 throw INTERP_KERNEL::Exception(oss.str().c_str());
10950 arrOut=arro.retn();
10951 arrIndexOut=arrIo.retn();
10955 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
10956 * (\ref numbering-indirect).
10957 * This method returns the result of the extraction ( specified by a set of ids with a slice given by \a idsOfSelectStart, \a idsOfSelectStop and \a idsOfSelectStep ).
10958 * The selection of extraction is done standardly in new2old format.
10959 * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
10961 * \param [in] idsOfSelectStart begin of set of ids of the input extraction (included)
10962 * \param [in] idsOfSelectStop end of set of ids of the input extraction (excluded)
10963 * \param [in] idsOfSelectStep
10964 * \param [in] arrIn arr origin array from which the extraction will be done.
10965 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
10966 * \param [out] arrOut the resulting array
10967 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
10968 * \sa MEDCouplingUMesh::ExtractFromIndexedArrays
10970 void MEDCouplingUMesh::ExtractFromIndexedArraysSlice(int idsOfSelectStart, int idsOfSelectStop, int idsOfSelectStep, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
10971 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
10973 if(!arrIn || !arrIndxIn)
10974 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input pointer is NULL !");
10975 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
10976 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
10977 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input arrays must have exactly one component !");
10978 int sz=DataArrayInt::GetNumberOfItemGivenBESRelative(idsOfSelectStart,idsOfSelectStop,idsOfSelectStep,"MEDCouplingUMesh::ExtractFromIndexedArraysSlice : Input slice ");
10979 const int *arrInPtr=arrIn->getConstPointer();
10980 const int *arrIndxPtr=arrIndxIn->getConstPointer();
10981 int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
10983 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
10984 int maxSizeOfArr=arrIn->getNumberOfTuples();
10985 MCAuto<DataArrayInt> arro=DataArrayInt::New();
10986 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
10987 arrIo->alloc((int)(sz+1),1);
10988 int idsIt=idsOfSelectStart;
10989 int *work=arrIo->getPointer();
10992 for(int i=0;i<sz;i++,work++,idsIt+=idsOfSelectStep)
10994 if(idsIt>=0 && idsIt<nbOfGrps)
10995 lgth+=arrIndxPtr[idsIt+1]-arrIndxPtr[idsIt];
10998 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " ! Must be in [0," << nbOfGrps << ") !";
10999 throw INTERP_KERNEL::Exception(oss.str().c_str());
11005 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " and at this pos arrIndxIn[" << idsIt;
11006 oss << "+1]-arrIndxIn[" << idsIt << "] < 0 ! The input index array is bugged !";
11007 throw INTERP_KERNEL::Exception(oss.str().c_str());
11010 arro->alloc(lgth,1);
11011 work=arro->getPointer();
11012 idsIt=idsOfSelectStart;
11013 for(int i=0;i<sz;i++,idsIt+=idsOfSelectStep)
11015 if(arrIndxPtr[idsIt]>=0 && arrIndxPtr[idsIt+1]<=maxSizeOfArr)
11016 work=std::copy(arrInPtr+arrIndxPtr[idsIt],arrInPtr+arrIndxPtr[idsIt+1],work);
11019 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " arrIndx[" << idsIt << "] must be >= 0 and arrIndx[";
11020 oss << idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
11021 throw INTERP_KERNEL::Exception(oss.str().c_str());
11024 arrOut=arro.retn();
11025 arrIndexOut=arrIo.retn();
11029 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11030 * This method builds an output pair (\b arrOut,\b arrIndexOut) that is a copy from \b arrIn for all cell ids \b not \b in [ \b idsOfSelectBg , \b idsOfSelectEnd ) and for
11031 * cellIds \b in [ \b idsOfSelectBg , \b idsOfSelectEnd ) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
11032 * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
11034 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
11035 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
11036 * \param [in] arrIn arr origin array from which the extraction will be done.
11037 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11038 * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg, \b idsOfSelectEnd )
11039 * \param [in] srcArrIndex index array of \b srcArr
11040 * \param [out] arrOut the resulting array
11041 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11043 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
11045 void MEDCouplingUMesh::SetPartOfIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11046 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
11047 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11049 if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11050 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArrays : presence of null pointer in input parameter !");
11051 MCAuto<DataArrayInt> arro=DataArrayInt::New();
11052 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11053 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11054 std::vector<bool> v(nbOfTuples,true);
11056 const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11057 const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11058 for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
11060 if(*it>=0 && *it<nbOfTuples)
11063 offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[*it+1]-arrIndxInPtr[*it]);
11067 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArrays : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
11068 throw INTERP_KERNEL::Exception(oss.str().c_str());
11071 srcArrIndexPtr=srcArrIndex->getConstPointer();
11072 arrIo->alloc(nbOfTuples+1,1);
11073 arro->alloc(arrIn->getNumberOfTuples()+offset,1);
11074 const int *arrInPtr=arrIn->getConstPointer();
11075 const int *srcArrPtr=srcArr->getConstPointer();
11076 int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
11077 int *arroPtr=arro->getPointer();
11078 for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
11082 arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
11083 *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
11087 std::size_t pos=std::distance(idsOfSelectBg,std::find(idsOfSelectBg,idsOfSelectEnd,ii));
11088 arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
11089 *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
11092 arrOut=arro.retn();
11093 arrIndexOut=arrIo.retn();
11097 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11098 * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
11100 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
11101 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
11102 * \param [in,out] arrInOut arr origin array from which the extraction will be done.
11103 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11104 * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg , \b idsOfSelectEnd )
11105 * \param [in] srcArrIndex index array of \b srcArr
11107 * \sa MEDCouplingUMesh::SetPartOfIndexedArrays
11109 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(const int *idsOfSelectBg, const int *idsOfSelectEnd, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
11110 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
11112 if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11113 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : presence of null pointer in input parameter !");
11114 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11115 const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11116 const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11117 int *arrInOutPtr=arrInOut->getPointer();
11118 const int *srcArrPtr=srcArr->getConstPointer();
11119 for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
11121 if(*it>=0 && *it<nbOfTuples)
11123 if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[*it+1]-arrIndxInPtr[*it])
11124 std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[*it]);
11127 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : On pos #" << std::distance(idsOfSelectBg,it) << " id (idsOfSelectBg[" << std::distance(idsOfSelectBg,it)<< "]) is " << *it << " arrIndxIn[id+1]-arrIndxIn[id]!=srcArrIndex[pos+1]-srcArrIndex[pos] !";
11128 throw INTERP_KERNEL::Exception(oss.str().c_str());
11133 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
11134 throw INTERP_KERNEL::Exception(oss.str().c_str());
11140 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
11141 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
11142 * This method start from id 0 that will be contained in output DataArrayInt. It searches then all neighbors of id0 looking at arrIn[arrIndxIn[0]:arrIndxIn[0+1]].
11143 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
11144 * A negative value in \b arrIn means that it is ignored.
11145 * 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.
11147 * \param [in] arrIn arr origin array from which the extraction will be done.
11148 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11149 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
11150 * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
11152 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn)
11154 int seed=0,nbOfDepthPeelingPerformed=0;
11155 return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
11159 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
11160 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
11161 * This method start from id 0 that will be contained in output DataArrayInt. It searches then all neighbors of id0 regarding arrIn[arrIndxIn[0]:arrIndxIn[0+1]].
11162 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
11163 * A negative value in \b arrIn means that it is ignored.
11164 * 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.
11165 * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
11166 * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
11167 * \param [in] arrIn arr origin array from which the extraction will be done.
11168 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11169 * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
11170 * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
11171 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
11172 * \sa MEDCouplingUMesh::partitionBySpreadZone
11174 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed)
11176 nbOfDepthPeelingPerformed=0;
11178 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
11179 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11182 DataArrayInt *ret=DataArrayInt::New(); ret->alloc(0,1);
11186 std::vector<bool> fetched(nbOfTuples,false);
11187 return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
11190 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg(std::vector<bool>& fetched, const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed)
11192 nbOfDepthPeelingPerformed=0;
11193 if(!seedBg || !seedEnd || !arrIn || !arrIndxIn)
11194 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg : some input pointer is NULL !");
11195 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11196 std::vector<bool> fetched2(nbOfTuples,false);
11198 for(const int *seedElt=seedBg;seedElt!=seedEnd;seedElt++,i++)
11200 if(*seedElt>=0 && *seedElt<nbOfTuples)
11201 { fetched[*seedElt]=true; fetched2[*seedElt]=true; }
11203 { std::ostringstream oss; oss << "MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg : At pos #" << i << " of seeds value is " << *seedElt << "! Should be in [0," << nbOfTuples << ") !"; throw INTERP_KERNEL::Exception(oss.str().c_str()); }
11205 const int *arrInPtr=arrIn->getConstPointer();
11206 const int *arrIndxPtr=arrIndxIn->getConstPointer();
11207 int targetNbOfDepthPeeling=nbOfDepthPeeling!=-1?nbOfDepthPeeling:std::numeric_limits<int>::max();
11208 std::vector<int> idsToFetch1(seedBg,seedEnd);
11209 std::vector<int> idsToFetch2;
11210 std::vector<int> *idsToFetch=&idsToFetch1;
11211 std::vector<int> *idsToFetchOther=&idsToFetch2;
11212 while(!idsToFetch->empty() && nbOfDepthPeelingPerformed<targetNbOfDepthPeeling)
11214 for(std::vector<int>::const_iterator it=idsToFetch->begin();it!=idsToFetch->end();it++)
11215 for(const int *it2=arrInPtr+arrIndxPtr[*it];it2!=arrInPtr+arrIndxPtr[*it+1];it2++)
11217 { fetched[*it2]=true; fetched2[*it2]=true; idsToFetchOther->push_back(*it2); }
11218 std::swap(idsToFetch,idsToFetchOther);
11219 idsToFetchOther->clear();
11220 nbOfDepthPeelingPerformed++;
11222 int lgth=(int)std::count(fetched2.begin(),fetched2.end(),true);
11224 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(lgth,1);
11225 int *retPtr=ret->getPointer();
11226 for(std::vector<bool>::const_iterator it=fetched2.begin();it!=fetched2.end();it++,i++)
11233 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11234 * This method builds an output pair (\b arrOut,\b arrIndexOut) that is a copy from \b arrIn for all cell ids \b not \b in [ \b idsOfSelectBg , \b idsOfSelectEnd ) and for
11235 * cellIds \b in [\b idsOfSelectBg, \b idsOfSelectEnd) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
11236 * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
11238 * \param [in] start begin of set of ids of the input extraction (included)
11239 * \param [in] end end of set of ids of the input extraction (excluded)
11240 * \param [in] step step of the set of ids in range mode.
11241 * \param [in] arrIn arr origin array from which the extraction will be done.
11242 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11243 * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
11244 * \param [in] srcArrIndex index array of \b srcArr
11245 * \param [out] arrOut the resulting array
11246 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11248 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx MEDCouplingUMesh::SetPartOfIndexedArrays
11250 void MEDCouplingUMesh::SetPartOfIndexedArraysSlice(int start, int end, int step, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11251 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
11252 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11254 if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11255 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSlice : presence of null pointer in input parameter !");
11256 MCAuto<DataArrayInt> arro=DataArrayInt::New();
11257 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11258 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11260 const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11261 const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11262 int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSlice : ");
11264 for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
11266 if(it>=0 && it<nbOfTuples)
11267 offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[it+1]-arrIndxInPtr[it]);
11270 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
11271 throw INTERP_KERNEL::Exception(oss.str().c_str());
11274 srcArrIndexPtr=srcArrIndex->getConstPointer();
11275 arrIo->alloc(nbOfTuples+1,1);
11276 arro->alloc(arrIn->getNumberOfTuples()+offset,1);
11277 const int *arrInPtr=arrIn->getConstPointer();
11278 const int *srcArrPtr=srcArr->getConstPointer();
11279 int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
11280 int *arroPtr=arro->getPointer();
11281 for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
11283 int pos=DataArray::GetPosOfItemGivenBESRelativeNoThrow(ii,start,end,step);
11286 arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
11287 *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
11291 arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
11292 *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
11295 arrOut=arro.retn();
11296 arrIndexOut=arrIo.retn();
11300 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11301 * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
11303 * \param [in] start begin of set of ids of the input extraction (included)
11304 * \param [in] end end of set of ids of the input extraction (excluded)
11305 * \param [in] step step of the set of ids in range mode.
11306 * \param [in,out] arrInOut arr origin array from which the extraction will be done.
11307 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11308 * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
11309 * \param [in] srcArrIndex index array of \b srcArr
11311 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSlice MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
11313 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(int start, int end, int step, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
11314 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
11316 if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11317 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : presence of null pointer in input parameter !");
11318 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11319 const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11320 const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11321 int *arrInOutPtr=arrInOut->getPointer();
11322 const int *srcArrPtr=srcArr->getConstPointer();
11323 int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : ");
11325 for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
11327 if(it>=0 && it<nbOfTuples)
11329 if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[it+1]-arrIndxInPtr[it])
11330 std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[it]);
11333 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " id (idsOfSelectBg[" << i << "]) is " << it << " arrIndxIn[id+1]-arrIndxIn[id]!=srcArrIndex[pos+1]-srcArrIndex[pos] !";
11334 throw INTERP_KERNEL::Exception(oss.str().c_str());
11339 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
11340 throw INTERP_KERNEL::Exception(oss.str().c_str());
11346 * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
11347 * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
11348 * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
11349 * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
11350 * The sum of measure field of returned mesh is equal to the sum of measure field of this.
11352 * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
11354 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
11356 checkFullyDefined();
11357 int mdim=getMeshDimension();
11358 int spaceDim=getSpaceDimension();
11360 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
11361 std::vector<DataArrayInt *> partition=partitionBySpreadZone();
11362 std::vector< MCAuto<DataArrayInt> > partitionAuto; partitionAuto.reserve(partition.size());
11363 std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayInt> > >(partitionAuto));
11364 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
11365 ret->setCoords(getCoords());
11366 ret->allocateCells((int)partition.size());
11368 for(std::vector<DataArrayInt *>::const_iterator it=partition.begin();it!=partition.end();it++)
11370 MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
11371 MCAuto<DataArrayInt> cell;
11375 cell=tmp->buildUnionOf2DMesh();
11378 cell=tmp->buildUnionOf3DMesh();
11381 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
11384 ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->getConstPointer()+1);
11387 ret->finishInsertingCells();
11392 * This method partitions \b this into contiguous zone.
11393 * This method only needs a well defined connectivity. Coordinates are not considered here.
11394 * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
11396 std::vector<DataArrayInt *> MEDCouplingUMesh::partitionBySpreadZone() const
11398 int nbOfCellsCur=getNumberOfCells();
11399 std::vector<DataArrayInt *> ret;
11400 if(nbOfCellsCur<=0)
11402 DataArrayInt *neigh=0,*neighI=0;
11403 computeNeighborsOfCells(neigh,neighI);
11404 MCAuto<DataArrayInt> neighAuto(neigh),neighIAuto(neighI);
11405 std::vector<bool> fetchedCells(nbOfCellsCur,false);
11406 std::vector< MCAuto<DataArrayInt> > ret2;
11408 while(seed<nbOfCellsCur)
11410 int nbOfPeelPerformed=0;
11411 ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,neigh,neighI,-1,nbOfPeelPerformed));
11412 seed=(int)std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false));
11414 for(std::vector< MCAuto<DataArrayInt> >::iterator it=ret2.begin();it!=ret2.end();it++)
11415 ret.push_back((*it).retn());
11420 * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
11421 * newly allocated DataArrayInt instance with 2 components ready to be interpreted as input of DataArrayInt::findRangeIdForEachTuple method.
11423 * \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.
11424 * \return a newly allocated DataArrayInt to be managed by the caller.
11425 * \throw In case of \a code has not the right format (typically of size 3*n)
11427 DataArrayInt *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<int>& code)
11429 MCAuto<DataArrayInt> ret=DataArrayInt::New();
11430 std::size_t nb=code.size()/3;
11431 if(code.size()%3!=0)
11432 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
11433 ret->alloc((int)nb,2);
11434 int *retPtr=ret->getPointer();
11435 for(std::size_t i=0;i<nb;i++,retPtr+=2)
11437 retPtr[0]=code[3*i+2];
11438 retPtr[1]=code[3*i+2]+code[3*i+1];
11444 * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
11445 * All cells in \a this are expected to be linear 3D cells.
11446 * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
11447 * It leads to an increase to number of cells.
11448 * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
11449 * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
11450 * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
11452 * \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.
11453 * For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
11454 * \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.
11455 * \param [out] n2oCells - A new instance of DataArrayInt holding, for each new cell,
11456 * an id of old cell producing it. The caller is to delete this array using
11457 * decrRef() as it is no more needed.
11458 * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
11460 * \warning This method operates on each cells in this independantly ! So it can leads to non conform mesh in returned value ! If you expect to have a conform mesh in output
11461 * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
11463 * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
11464 * \throw If \a this is not fully constituted with linear 3D cells.
11465 * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
11467 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayInt *& n2oCells, int& nbOfAdditionalPoints) const
11469 INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
11470 checkConnectivityFullyDefined();
11471 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
11472 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
11473 int nbOfCells(getNumberOfCells()),nbNodes(getNumberOfNodes());
11474 MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
11475 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfCells,1);
11476 int *retPt(ret->getPointer());
11477 MCAuto<DataArrayInt> newConn(DataArrayInt::New()); newConn->alloc(0,1);
11478 MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
11479 const int *oldc(_nodal_connec->begin());
11480 const int *oldci(_nodal_connec_index->begin());
11481 const double *coords(_coords->begin());
11482 for(int i=0;i<nbOfCells;i++,oldci++,retPt++)
11484 std::vector<int> a; std::vector<double> b;
11485 INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
11486 std::size_t nbOfTet(a.size()/4); *retPt=(int)nbOfTet;
11487 const int *aa(&a[0]);
11490 for(std::vector<int>::iterator it=a.begin();it!=a.end();it++)
11492 *it=(-(*(it))-1+nbNodes);
11493 addPts->insertAtTheEnd(b.begin(),b.end());
11494 nbNodes+=(int)b.size()/3;
11496 for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
11497 newConn->insertAtTheEnd(aa,aa+4);
11499 if(!addPts->empty())
11501 addPts->rearrange(3);
11502 nbOfAdditionalPoints=addPts->getNumberOfTuples();
11503 addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
11504 ret0->setCoords(addPts);
11508 nbOfAdditionalPoints=0;
11509 ret0->setCoords(getCoords());
11511 ret0->setNodalConnectivity(newConn);
11513 ret->computeOffsetsFull();
11514 n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
11515 return ret0.retn();
11519 * It is the linear part of MEDCouplingUMesh::split2DCells. Here no additionnal nodes will be added in \b this. So coordinates pointer remain unchanged (is not even touch).
11521 * \sa MEDCouplingUMesh::split2DCells
11523 void MEDCouplingUMesh::split2DCellsLinear(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI)
11525 checkConnectivityFullyDefined();
11526 int ncells(getNumberOfCells()),lgthToReach(getNodalConnectivityArrayLen()+subNodesInSeg->getNumberOfTuples());
11527 MCAuto<DataArrayInt> c(DataArrayInt::New()); c->alloc((std::size_t)lgthToReach);
11528 const int *subPtr(subNodesInSeg->begin()),*subIPtr(subNodesInSegI->begin()),*descPtr(desc->begin()),*descIPtr(descI->begin()),*oldConn(getNodalConnectivity()->begin());
11529 int *cPtr(c->getPointer()),*ciPtr(getNodalConnectivityIndex()->getPointer());
11530 int prevPosOfCi(ciPtr[0]);
11531 for(int i=0;i<ncells;i++,ciPtr++,descIPtr++)
11533 int offset(descIPtr[0]),sz(descIPtr[1]-descIPtr[0]),deltaSz(0);
11534 *cPtr++=(int)INTERP_KERNEL::NORM_POLYGON; *cPtr++=oldConn[prevPosOfCi+1];
11535 for(int j=0;j<sz;j++)
11537 int offset2(subIPtr[descPtr[offset+j]]),sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]);
11538 for(int k=0;k<sz2;k++)
11539 *cPtr++=subPtr[offset2+k];
11541 *cPtr++=oldConn[prevPosOfCi+j+2];
11544 prevPosOfCi=ciPtr[1];
11545 ciPtr[1]=ciPtr[0]+1+sz+deltaSz;//sz==old nb of nodes because (nb of subedges=nb of nodes for polygons)
11548 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCellsLinear : Some of edges to be split are orphan !");
11549 _nodal_connec->decrRef();
11550 _nodal_connec=c.retn(); _types.clear(); _types.insert(INTERP_KERNEL::NORM_POLYGON);
11553 int InternalAddPoint(const INTERP_KERNEL::Edge *e, int id, const double *coo, int startId, int endId, DataArrayDouble& addCoo, int& nodesCnter)
11559 int ret(nodesCnter++);
11561 e->getMiddleOfPoints(coo+2*startId,coo+2*endId,newPt);
11562 addCoo.insertAtTheEnd(newPt,newPt+2);
11567 int InternalAddPointOriented(const INTERP_KERNEL::Edge *e, int id, const double *coo, int startId, int endId, DataArrayDouble& addCoo, int& nodesCnter)
11573 int ret(nodesCnter++);
11575 e->getMiddleOfPointsOriented(coo+2*startId,coo+2*endId,newPt);
11576 addCoo.insertAtTheEnd(newPt,newPt+2);
11584 void EnterTheResultOf2DCellFirst(const INTERP_KERNEL::Edge *e, int start, int stp, int nbOfEdges, bool linOrArc, const double *coords, const int *connBg, int offset, DataArrayInt *newConnOfCell, DataArrayDouble *appendedCoords, std::vector<int>& middles)
11587 int trueStart(start>=0?start:nbOfEdges+start);
11588 tmp[0]=linOrArc?(int)INTERP_KERNEL::NORM_QPOLYG:(int)INTERP_KERNEL::NORM_POLYGON; tmp[1]=connBg[trueStart]; tmp[2]=connBg[stp];
11589 newConnOfCell->insertAtTheEnd(tmp,tmp+3);
11594 int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11595 InternalAddPointOriented(e,-1,coords,tmp[1],tmp[2],*appendedCoords,tmp2);
11596 middles.push_back(tmp3+offset);
11599 middles.push_back(connBg[trueStart+nbOfEdges]);
11603 void EnterTheResultOf2DCellMiddle(const INTERP_KERNEL::Edge *e, int start, int stp, int nbOfEdges, bool linOrArc, const double *coords, const int *connBg, int offset, DataArrayInt *newConnOfCell, DataArrayDouble *appendedCoords, std::vector<int>& middles)
11605 int tmpSrt(newConnOfCell->back()),tmpEnd(connBg[stp]);
11606 newConnOfCell->pushBackSilent(tmpEnd);
11611 int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11612 InternalAddPointOriented(e,-1,coords,tmpSrt,tmpEnd,*appendedCoords,tmp2);
11613 middles.push_back(tmp3+offset);
11616 middles.push_back(connBg[start+nbOfEdges]);
11620 void EnterTheResultOf2DCellEnd(const INTERP_KERNEL::Edge *e, int start, int stp, int nbOfEdges, bool linOrArc, const double *coords, const int *connBg, int offset, DataArrayInt *newConnOfCell, DataArrayDouble *appendedCoords, std::vector<int>& middles)
11622 // only the quadratic point to deal with:
11627 int tmpSrt(connBg[start]),tmpEnd(connBg[stp]);
11628 int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11629 InternalAddPointOriented(e,-1,coords,tmpSrt,tmpEnd,*appendedCoords,tmp2);
11630 middles.push_back(tmp3+offset);
11633 middles.push_back(connBg[start+nbOfEdges]);
11640 * Returns true if a colinearization has been found in the given cell. If false is returned the content pushed in \a newConnOfCell is equal to [ \a connBg , \a connEnd ) .
11641 * \a appendedCoords is a DataArrayDouble instance with number of components equal to one (even if the items are pushed by pair).
11643 bool MEDCouplingUMesh::Colinearize2DCell(const double *coords, const int *connBg, const int *connEnd, int offset, DataArrayInt *newConnOfCell, DataArrayDouble *appendedCoords)
11645 std::size_t sz(std::distance(connBg,connEnd));
11646 if(sz<3)//3 because 2+1(for the cell type) and 2 is the minimal number of edges of 2D cell.
11647 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Colinearize2DCell : the input cell has invalid format !");
11649 INTERP_KERNEL::AutoPtr<int> tmpConn(new int[sz]);
11650 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connBg[0]));
11651 unsigned nbs(cm.getNumberOfSons2(connBg+1,sz));
11652 unsigned nbOfHit(0); // number of fusions operated
11653 int posBaseElt(0),posEndElt(0),nbOfTurn(0);
11654 const unsigned int maxNbOfHit = cm.isQuadratic() ? nbs-2 : nbs-3; // a quad cell is authorized to end up with only two edges, a linear one has to keep 3 at least
11655 INTERP_KERNEL::NormalizedCellType typeOfSon;
11656 std::vector<int> middles;
11658 for(;(nbOfTurn+nbOfHit)<nbs;nbOfTurn++)
11660 cm.fillSonCellNodalConnectivity2(posBaseElt,connBg+1,sz,tmpConn,typeOfSon);
11661 std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
11662 INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11663 posEndElt = posBaseElt+1;
11665 // Look backward first: are the final edges of the cells colinear with the first ones?
11666 // This initializes posBaseElt.
11669 for(unsigned i=1;i<nbs && nbOfHit<maxNbOfHit;i++) // 2nd condition is to avoid ending with a cell wih one single edge
11671 cm.fillSonCellNodalConnectivity2(nbs-i,connBg+1,sz,tmpConn,typeOfSon);
11672 INTERP_KERNEL::Edge *eCand(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11673 INTERP_KERNEL::EdgeIntersector *eint(INTERP_KERNEL::Edge::BuildIntersectorWith(e,eCand));
11674 bool isColinear=eint->areColinears();
11687 // Now move forward:
11688 const unsigned fwdStart = (nbOfTurn == 0 ? 0 : posBaseElt); // the first element to be inspected going forward
11689 for(unsigned j=fwdStart+1;j<nbs && nbOfHit<maxNbOfHit;j++) // 2nd condition is to avoid ending with a cell wih one single edge
11691 cm.fillSonCellNodalConnectivity2((int)j,connBg+1,sz,tmpConn,typeOfSon); // get edge #j's connectivity
11692 INTERP_KERNEL::Edge *eCand(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11693 INTERP_KERNEL::EdgeIntersector *eint(INTERP_KERNEL::Edge::BuildIntersectorWith(e,eCand));
11694 bool isColinear(eint->areColinears());
11706 //push [posBaseElt,posEndElt) in newConnOfCell using e
11707 // The if clauses below are (volontary) not mutually exclusive: on a quad cell with 2 edges, the end of the connectivity is also its begining!
11709 // at the begining of the connectivity (insert type)
11710 EnterTheResultOf2DCellFirst(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
11711 else if((nbOfHit+nbOfTurn) != (nbs-1))
11713 EnterTheResultOf2DCellMiddle(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
11714 if ((nbOfHit+nbOfTurn) == (nbs-1))
11715 // at the end (only quad points to deal with)
11716 EnterTheResultOf2DCellEnd(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
11717 posBaseElt=posEndElt;
11720 if(!middles.empty())
11721 newConnOfCell->insertAtTheEnd(middles.begin(),middles.end());
11726 * It is the quadratic part of MEDCouplingUMesh::split2DCells. Here some additionnal nodes can be added at the end of coordinates array object.
11728 * \return int - the number of new nodes created.
11729 * \sa MEDCouplingUMesh::split2DCells
11731 int MEDCouplingUMesh::split2DCellsQuadratic(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *mid, const DataArrayInt *midI)
11733 checkConsistencyLight();
11734 int ncells(getNumberOfCells()),lgthToReach(getNodalConnectivityArrayLen()+2*subNodesInSeg->getNumberOfTuples()),nodesCnt(getNumberOfNodes());
11735 MCAuto<DataArrayInt> c(DataArrayInt::New()); c->alloc((std::size_t)lgthToReach);
11736 MCAuto<DataArrayDouble> addCoo(DataArrayDouble::New()); addCoo->alloc(0,1);
11737 const int *subPtr(subNodesInSeg->begin()),*subIPtr(subNodesInSegI->begin()),*descPtr(desc->begin()),*descIPtr(descI->begin()),*oldConn(getNodalConnectivity()->begin());
11738 const int *midPtr(mid->begin()),*midIPtr(midI->begin());
11739 const double *oldCoordsPtr(getCoords()->begin());
11740 int *cPtr(c->getPointer()),*ciPtr(getNodalConnectivityIndex()->getPointer());
11741 int prevPosOfCi(ciPtr[0]);
11742 for(int i=0;i<ncells;i++,ciPtr++,descIPtr++)
11744 int offset(descIPtr[0]),sz(descIPtr[1]-descIPtr[0]),deltaSz(sz);
11745 for(int j=0;j<sz;j++)
11746 { int sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]); deltaSz+=sz2; }
11747 *cPtr++=(int)INTERP_KERNEL::NORM_QPOLYG; cPtr[0]=oldConn[prevPosOfCi+1];
11748 for(int j=0;j<sz;j++)//loop over subedges of oldConn
11750 int offset2(subIPtr[descPtr[offset+j]]),sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]),offset3(midIPtr[descPtr[offset+j]]);
11754 cPtr[1]=oldConn[prevPosOfCi+2+j];
11755 cPtr[deltaSz]=oldConn[prevPosOfCi+1+j+sz]; cPtr++;
11758 std::vector<INTERP_KERNEL::Node *> ns(3);
11759 ns[0]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+j]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+j]+1]);
11760 ns[1]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+(1+j)%sz]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+(1+j)%sz]+1]);
11761 ns[2]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+sz+j]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+sz+j]+1]);
11762 MCAuto<INTERP_KERNEL::Edge> e(INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(ns));
11763 for(int k=0;k<sz2;k++)//loop over subsplit of current subedge
11765 cPtr[1]=subPtr[offset2+k];
11766 cPtr[deltaSz]=InternalAddPoint(e,midPtr[offset3+k],oldCoordsPtr,cPtr[0],cPtr[1],*addCoo,nodesCnt); cPtr++;
11768 int tmpEnd(oldConn[prevPosOfCi+1+(j+1)%sz]);
11770 { cPtr[1]=tmpEnd; }
11771 cPtr[deltaSz]=InternalAddPoint(e,midPtr[offset3+sz2],oldCoordsPtr,cPtr[0],tmpEnd,*addCoo,nodesCnt); cPtr++;
11773 prevPosOfCi=ciPtr[1]; cPtr+=deltaSz;
11774 ciPtr[1]=ciPtr[0]+1+2*deltaSz;//sz==old nb of nodes because (nb of subedges=nb of nodes for polygons)
11777 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCellsQuadratic : Some of edges to be split are orphan !");
11778 _nodal_connec->decrRef();
11779 _nodal_connec=c.retn(); _types.clear(); _types.insert(INTERP_KERNEL::NORM_QPOLYG);
11780 addCoo->rearrange(2);
11781 MCAuto<DataArrayDouble> coo(DataArrayDouble::Aggregate(getCoords(),addCoo));//info are copied from getCoords() by using Aggregate
11783 return addCoo->getNumberOfTuples();
11786 void MEDCouplingUMesh::ComputeAllTypesInternal(std::set<INTERP_KERNEL::NormalizedCellType>& types, const DataArrayInt *nodalConnec, const DataArrayInt *nodalConnecIndex)
11788 if(nodalConnec && nodalConnecIndex)
11791 const int *conn(nodalConnec->getConstPointer()),*connIndex(nodalConnecIndex->getConstPointer());
11792 int nbOfElem(nodalConnecIndex->getNbOfElems()-1);
11794 for(const int *pt=connIndex;pt!=connIndex+nbOfElem;pt++)
11795 types.insert((INTERP_KERNEL::NormalizedCellType)conn[*pt]);
11799 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
11800 _own_cell(true),_cell_id(-1),_nb_cell(0)
11805 _nb_cell=mesh->getNumberOfCells();
11809 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
11817 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_cell(itc),
11818 _own_cell(false),_cell_id(bg-1),
11825 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
11828 if(_cell_id<_nb_cell)
11837 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
11843 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
11845 return new MEDCouplingUMeshCellByTypeIterator(_mesh);
11848 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
11854 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh, INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_type(type),
11862 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
11868 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
11873 int MEDCouplingUMeshCellEntry::getNumberOfElems() const
11878 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
11880 return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
11883 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
11888 _nb_cell=mesh->getNumberOfCells();
11892 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
11899 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
11901 const int *c=_mesh->getNodalConnectivity()->getConstPointer();
11902 const int *ci=_mesh->getNodalConnectivityIndex()->getConstPointer();
11903 if(_cell_id<_nb_cell)
11905 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
11906 int nbOfElems=(int)std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type)));
11907 int startId=_cell_id;
11908 _cell_id+=nbOfElems;
11909 return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
11915 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
11919 _conn=mesh->getNodalConnectivity()->getPointer();
11920 _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
11924 void MEDCouplingUMeshCell::next()
11926 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
11931 _conn_lgth=_conn_indx[1]-_conn_indx[0];
11934 std::string MEDCouplingUMeshCell::repr() const
11936 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
11938 std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
11940 std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<int>(oss," "));
11944 return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
11947 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
11949 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
11950 return (INTERP_KERNEL::NormalizedCellType)_conn[0];
11952 return INTERP_KERNEL::NORM_ERROR;
11955 const int *MEDCouplingUMeshCell::getAllConn(int& lgth) const
11958 if(_conn_lgth!=NOTICABLE_FIRST_VAL)