1 // Copyright (C) 2007-2016 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 "MEDCouplingFieldDouble.hxx"
24 #include "MEDCouplingSkyLineArray.hxx"
25 #include "CellModel.hxx"
26 #include "VolSurfUser.txx"
27 #include "InterpolationUtils.hxx"
28 #include "PointLocatorAlgos.txx"
30 #include "BBTreeDst.txx"
31 #include "SplitterTetra.hxx"
32 #include "DiameterCalculator.hxx"
33 #include "DirectedBoundingBox.hxx"
34 #include "InterpKernelMatrixTools.hxx"
35 #include "InterpKernelMeshQuality.hxx"
36 #include "InterpKernelCellSimplify.hxx"
37 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
38 #include "InterpKernelAutoPtr.hxx"
39 #include "InterpKernelGeo2DNode.hxx"
40 #include "InterpKernelGeo2DEdgeLin.hxx"
41 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
42 #include "InterpKernelGeo2DQuadraticPolygon.hxx"
51 using namespace MEDCoupling;
53 double MEDCouplingUMesh::EPS_FOR_POLYH_ORIENTATION=1.e-14;
56 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 };
57 const int MEDCouplingUMesh::MEDCOUPLING2VTKTYPETRADUCER[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};
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());
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());
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());
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());
270 std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " in connectivity ! sounds bad !";
271 throw INTERP_KERNEL::Exception(oss.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());
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());
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());
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;
676 class MicroEdgesGenerator2D
679 MicroEdgesGenerator2D(const INTERP_KERNEL::CellModel& cm):_cm(cm) { }
680 unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfMicroEdges(); }
681 unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillMicroEdgeNodalConnectivity(sonId,nodalConn,sonNodalConn,typeOfSon); }
682 static const int DELTA=1;
684 const INTERP_KERNEL::CellModel& _cm;
687 class MicroEdgesGenerator3D
690 MicroEdgesGenerator3D(const INTERP_KERNEL::CellModel& cm):_cm(cm) { }
691 unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfMicroEdges(); }
692 unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillMicroEdgeNodalConnectivity(sonId,nodalConn,sonNodalConn,typeOfSon); }
693 static const int DELTA=2;
695 const INTERP_KERNEL::CellModel& _cm;
701 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
702 * this->getMeshDimension(), that bound cells of \a this mesh. In addition arrays
703 * describing correspondence between cells of \a this and the result meshes are
704 * returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending connectivity,
705 * i.e. enumerate cells of the result mesh bounding each cell of \a this mesh. The
706 * arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
707 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
708 * \warning For speed reasons, this method does not check if node ids in the nodal
709 * connectivity correspond to the size of node coordinates array.
710 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
711 * to write this mesh to the MED file, its cells must be sorted using
712 * sortCellsInMEDFileFrmt().
713 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
714 * each cell of \a this mesh.
715 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
716 * dividing cell ids in \a desc into groups each referring to one
717 * cell of \a this mesh. Its every element (except the last one) is an index
718 * pointing to the first id of a group of cells. For example cells of the
719 * result mesh bounding the cell #1 of \a this mesh are described by following
721 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
722 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
723 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
724 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
725 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
726 * by each cell of the result mesh.
727 * \param [in,out] revDescIndx - the array, of length one more than number of cells
728 * in the result mesh,
729 * dividing cell ids in \a revDesc into groups each referring to one
730 * cell of the result mesh the same way as \a descIndx divides \a desc.
731 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
732 * delete this mesh using decrRef() as it is no more needed.
733 * \throw If the coordinates array is not set.
734 * \throw If the nodal connectivity of cells is node defined.
735 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
736 * revDescIndx == NULL.
738 * \if ENABLE_EXAMPLES
739 * \ref cpp_mcumesh_buildDescendingConnectivity "Here is a C++ example".<br>
740 * \ref py_mcumesh_buildDescendingConnectivity "Here is a Python example".
742 * \sa buildDescendingConnectivity2()
744 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
746 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
750 * \a this has to have a mesh dimension equal to 3. If it is not the case an INTERP_KERNEL::Exception will be thrown.
751 * This behaves exactly as MEDCouplingUMesh::buildDescendingConnectivity does except that this method compute directly the transition from mesh dimension 3 to sub edges (dimension 1)
752 * in one shot. That is to say that this method is equivalent to 2 successive calls to MEDCouplingUMesh::buildDescendingConnectivity.
753 * This method returns 4 arrays and a mesh as MEDCouplingUMesh::buildDescendingConnectivity does.
754 * \sa MEDCouplingUMesh::buildDescendingConnectivity
756 MEDCouplingUMesh *MEDCouplingUMesh::explode3DMeshTo1D(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
759 if(getMeshDimension()!=3)
760 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explode3DMeshTo1D : This has to have a mesh dimension to 3 !");
761 return buildDescendingConnectivityGen<MinusTwoSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
765 * This method computes the micro edges constituting each cell in \a this. Micro edge is an edge for non quadratic cells. Micro edge is an half edge for quadratic cells.
766 * This method works for both meshes with mesh dimenstion equal to 2 or 3. Dynamical cells are not supported (polygons, polyhedrons...)
768 * \sa explode3DMeshTo1D, buildDescendingConnectiviy
770 MEDCouplingUMesh *MEDCouplingUMesh::explodeMeshIntoMicroEdges(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
773 switch(getMeshDimension())
776 return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
778 return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
780 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explodeMeshIntoMicroEdges : Only 2D and 3D supported !");
785 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
786 * this->getMeshDimension(), that bound cells of \a this mesh. In
787 * addition arrays describing correspondence between cells of \a this and the result
788 * meshes are returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending
789 * connectivity, i.e. enumerate cells of the result mesh bounding each cell of \a this
790 * mesh. This method differs from buildDescendingConnectivity() in that apart
791 * from cell ids, \a desc returns mutual orientation of cells in \a this and the
792 * result meshes. So a positive id means that order of nodes in corresponding cells
793 * of two meshes is same, and a negative id means a reverse order of nodes. Since a
794 * cell with id #0 can't be negative, the array \a desc returns ids in FORTRAN mode,
795 * i.e. cell ids are one-based.
796 * Arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
797 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
798 * \warning For speed reasons, this method does not check if node ids in the nodal
799 * connectivity correspond to the size of node coordinates array.
800 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
801 * to write this mesh to the MED file, its cells must be sorted using
802 * sortCellsInMEDFileFrmt().
803 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
804 * each cell of \a this mesh.
805 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
806 * dividing cell ids in \a desc into groups each referring to one
807 * cell of \a this mesh. Its every element (except the last one) is an index
808 * pointing to the first id of a group of cells. For example cells of the
809 * result mesh bounding the cell #1 of \a this mesh are described by following
811 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
812 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
813 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
814 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
815 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
816 * by each cell of the result mesh.
817 * \param [in,out] revDescIndx - the array, of length one more than number of cells
818 * in the result mesh,
819 * dividing cell ids in \a revDesc into groups each referring to one
820 * cell of the result mesh the same way as \a descIndx divides \a desc.
821 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This result mesh
822 * shares the node coordinates array with \a this mesh. The caller is to
823 * delete this mesh using decrRef() as it is no more needed.
824 * \throw If the coordinates array is not set.
825 * \throw If the nodal connectivity of cells is node defined.
826 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
827 * revDescIndx == NULL.
829 * \if ENABLE_EXAMPLES
830 * \ref cpp_mcumesh_buildDescendingConnectivity2 "Here is a C++ example".<br>
831 * \ref py_mcumesh_buildDescendingConnectivity2 "Here is a Python example".
833 * \sa buildDescendingConnectivity()
835 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
837 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingOrientationSensitiveNbrer);
841 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
842 * For speed reasons no check of this will be done. This method calls
843 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
844 * This method lists cell by cell in \b this which are its neighbors. To compute the result
845 * only connectivities are considered.
846 * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
847 * The format of return is hence \ref numbering-indirect.
849 * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly
850 * allocated and should be dealt by the caller. \b neighborsIndx 2nd output
851 * parameter allows to select the right part in this array (\ref numbering-indirect). The number of tuples
852 * is equal to the last values in \b neighborsIndx.
853 * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be
854 * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
856 void MEDCouplingUMesh::computeNeighborsOfCells(DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx) const
858 MCAuto<DataArrayInt> desc=DataArrayInt::New();
859 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
860 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
861 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
862 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
864 ComputeNeighborsOfCellsAdv(desc,descIndx,revDesc,revDescIndx,neighbors,neighborsIndx);
868 * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm
869 * of MEDCouplingUMesh::computeNeighborsOfCells.
870 * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is
871 * typically the case to extract a set a neighbours,
872 * excluding a set of meshdim-1 cells in input descending connectivity.
873 * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx (\ref numbering-indirect) input params are
874 * the result of MEDCouplingUMesh::buildDescendingConnectivity.
875 * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities
877 * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
879 * \param [in] desc descending connectivity array.
880 * \param [in] descIndx descending connectivity index array used to walk through \b desc (\ref numbering-indirect).
881 * \param [in] revDesc reverse descending connectivity array.
882 * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc (\ref numbering-indirect).
883 * \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
884 * parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
885 * \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.
887 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayInt *desc, const DataArrayInt *descIndx, const DataArrayInt *revDesc, const DataArrayInt *revDescIndx,
888 DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx)
890 if(!desc || !descIndx || !revDesc || !revDescIndx)
891 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
892 const int *descPtr=desc->getConstPointer();
893 const int *descIPtr=descIndx->getConstPointer();
894 const int *revDescPtr=revDesc->getConstPointer();
895 const int *revDescIPtr=revDescIndx->getConstPointer();
897 int nbCells=descIndx->getNumberOfTuples()-1;
898 MCAuto<DataArrayInt> out0=DataArrayInt::New();
899 MCAuto<DataArrayInt> out1=DataArrayInt::New(); out1->alloc(nbCells+1,1);
900 int *out1Ptr=out1->getPointer();
902 out0->reserve(desc->getNumberOfTuples());
903 for(int i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
905 for(const int *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
907 std::set<int> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
909 out0->insertAtTheEnd(s.begin(),s.end());
911 *out1Ptr=out0->getNumberOfTuples();
913 neighbors=out0.retn();
914 neighborsIndx=out1.retn();
918 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
919 * For speed reasons no check of this will be done. This method calls
920 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
921 * This method lists node by node in \b this which are its neighbors. To compute the result
922 * only connectivities are considered.
923 * The neighbor nodes of node having id 'nodeId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
925 * \param [out] neighbors is an array storing all the neighbors of all nodes in \b this. This array
926 * is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
927 * parameter allows to select the right part in this array (\ref numbering-indirect).
928 * The number of tuples is equal to the last values in \b neighborsIndx.
929 * \param [out] neighborsIdx is an array of size this->getNumberOfCells()+1 newly allocated and should
930 * be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
932 void MEDCouplingUMesh::computeNeighborsOfNodes(DataArrayInt *&neighbors, DataArrayInt *&neighborsIdx) const
935 int mdim(getMeshDimension()),nbNodes(getNumberOfNodes());
936 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descIndx(DataArrayInt::New()),revDesc(DataArrayInt::New()),revDescIndx(DataArrayInt::New());
937 MCAuto<MEDCouplingUMesh> mesh1D;
942 mesh1D=explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx);
947 mesh1D=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
952 mesh1D=const_cast<MEDCouplingUMesh *>(this);
958 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2,1] !");
961 desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=0; revDescIndx=0;
962 mesh1D->getReverseNodalConnectivity(desc,descIndx);
963 MCAuto<DataArrayInt> ret0(DataArrayInt::New());
964 ret0->alloc(desc->getNumberOfTuples(),1);
965 int *r0Pt(ret0->getPointer());
966 const int *c1DPtr(mesh1D->getNodalConnectivity()->begin()),*rn(desc->begin()),*rni(descIndx->begin());
967 for(int i=0;i<nbNodes;i++,rni++)
969 for(const int *oneDCellIt=rn+rni[0];oneDCellIt!=rn+rni[1];oneDCellIt++)
970 *r0Pt++=c1DPtr[3*(*oneDCellIt)+1]==i?c1DPtr[3*(*oneDCellIt)+2]:c1DPtr[3*(*oneDCellIt)+1];
972 neighbors=ret0.retn();
973 neighborsIdx=descIndx.retn();
979 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
980 * For speed reasons no check of this will be done.
982 template<class SonsGenerator>
983 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivityGen(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx, DimM1DescNbrer nbrer) const
985 if(!desc || !descIndx || !revDesc || !revDescIndx)
986 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildDescendingConnectivityGen : present of a null pointer in input !");
987 checkConnectivityFullyDefined();
988 int nbOfCells=getNumberOfCells();
989 int nbOfNodes=getNumberOfNodes();
990 MCAuto<DataArrayInt> revNodalIndx=DataArrayInt::New(); revNodalIndx->alloc(nbOfNodes+1,1); revNodalIndx->fillWithZero();
991 int *revNodalIndxPtr=revNodalIndx->getPointer();
992 const int *conn=_nodal_connec->getConstPointer();
993 const int *connIndex=_nodal_connec_index->getConstPointer();
994 std::string name="Mesh constituent of "; name+=getName();
995 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(name,getMeshDimension()-SonsGenerator::DELTA);
996 ret->setCoords(getCoords());
997 ret->allocateCells(2*nbOfCells);
998 descIndx->alloc(nbOfCells+1,1);
999 MCAuto<DataArrayInt> revDesc2(DataArrayInt::New()); revDesc2->reserve(2*nbOfCells);
1000 int *descIndxPtr=descIndx->getPointer(); *descIndxPtr++=0;
1001 for(int eltId=0;eltId<nbOfCells;eltId++,descIndxPtr++)
1003 int pos=connIndex[eltId];
1004 int posP1=connIndex[eltId+1];
1005 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[pos]);
1006 SonsGenerator sg(cm);
1007 unsigned nbOfSons=sg.getNumberOfSons2(conn+pos+1,posP1-pos-1);
1008 INTERP_KERNEL::AutoPtr<int> tmp=new int[posP1-pos];
1009 for(unsigned i=0;i<nbOfSons;i++)
1011 INTERP_KERNEL::NormalizedCellType cmsId;
1012 unsigned nbOfNodesSon=sg.fillSonCellNodalConnectivity2(i,conn+pos+1,posP1-pos-1,tmp,cmsId);
1013 for(unsigned k=0;k<nbOfNodesSon;k++)
1015 revNodalIndxPtr[tmp[k]+1]++;
1016 ret->insertNextCell(cmsId,nbOfNodesSon,tmp);
1017 revDesc2->pushBackSilent(eltId);
1019 descIndxPtr[0]=descIndxPtr[-1]+(int)nbOfSons;
1021 int nbOfCellsM1=ret->getNumberOfCells();
1022 std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<int>());
1023 MCAuto<DataArrayInt> revNodal=DataArrayInt::New(); revNodal->alloc(revNodalIndx->back(),1);
1024 std::fill(revNodal->getPointer(),revNodal->getPointer()+revNodalIndx->back(),-1);
1025 int *revNodalPtr=revNodal->getPointer();
1026 const int *connM1=ret->getNodalConnectivity()->getConstPointer();
1027 const int *connIndexM1=ret->getNodalConnectivityIndex()->getConstPointer();
1028 for(int eltId=0;eltId<nbOfCellsM1;eltId++)
1030 const int *strtNdlConnOfCurCell=connM1+connIndexM1[eltId]+1;
1031 const int *endNdlConnOfCurCell=connM1+connIndexM1[eltId+1];
1032 for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
1033 if(*iter>=0)//for polyhedrons
1034 *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind2nd(std::equal_to<int>(),-1))=eltId;
1037 DataArrayInt *commonCells=0,*commonCellsI=0;
1038 FindCommonCellsAlg(3,0,ret->getNodalConnectivity(),ret->getNodalConnectivityIndex(),revNodal,revNodalIndx,commonCells,commonCellsI);
1039 MCAuto<DataArrayInt> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1040 const int *commonCellsPtr(commonCells->getConstPointer()),*commonCellsIPtr(commonCellsI->getConstPointer());
1041 int newNbOfCellsM1=-1;
1042 MCAuto<DataArrayInt> o2nM1=DataArrayInt::ConvertIndexArrayToO2N(nbOfCellsM1,commonCells->begin(),
1043 commonCellsI->begin(),commonCellsI->end(),newNbOfCellsM1);
1044 std::vector<bool> isImpacted(nbOfCellsM1,false);
1045 for(const int *work=commonCellsI->begin();work!=commonCellsI->end()-1;work++)
1046 for(int work2=work[0];work2!=work[1];work2++)
1047 isImpacted[commonCellsPtr[work2]]=true;
1048 const int *o2nM1Ptr=o2nM1->getConstPointer();
1049 MCAuto<DataArrayInt> n2oM1=o2nM1->invertArrayO2N2N2OBis(newNbOfCellsM1);
1050 const int *n2oM1Ptr=n2oM1->getConstPointer();
1051 MCAuto<MEDCouplingUMesh> ret2=static_cast<MEDCouplingUMesh *>(ret->buildPartOfMySelf(n2oM1->begin(),n2oM1->end(),true));
1052 ret2->copyTinyInfoFrom(this);
1053 desc->alloc(descIndx->back(),1);
1054 int *descPtr=desc->getPointer();
1055 const INTERP_KERNEL::CellModel& cmsDft=INTERP_KERNEL::CellModel::GetCellModel(INTERP_KERNEL::NORM_POINT1);
1056 for(int i=0;i<nbOfCellsM1;i++,descPtr++)
1059 *descPtr=nbrer(o2nM1Ptr[i],0,cmsDft,false,0,0);
1062 if(i!=n2oM1Ptr[o2nM1Ptr[i]])
1064 const INTERP_KERNEL::CellModel& cms=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connM1[connIndexM1[i]]);
1065 *descPtr=nbrer(o2nM1Ptr[i],connIndexM1[i+1]-connIndexM1[i]-1,cms,true,connM1+connIndexM1[n2oM1Ptr[o2nM1Ptr[i]]]+1,connM1+connIndexM1[i]+1);
1068 *descPtr=nbrer(o2nM1Ptr[i],0,cmsDft,false,0,0);
1071 revDesc->reserve(newNbOfCellsM1);
1072 revDescIndx->alloc(newNbOfCellsM1+1,1);
1073 int *revDescIndxPtr=revDescIndx->getPointer(); *revDescIndxPtr++=0;
1074 const int *revDesc2Ptr=revDesc2->getConstPointer();
1075 for(int i=0;i<newNbOfCellsM1;i++,revDescIndxPtr++)
1077 int oldCellIdM1=n2oM1Ptr[i];
1078 if(!isImpacted[oldCellIdM1])
1080 revDesc->pushBackSilent(revDesc2Ptr[oldCellIdM1]);
1081 revDescIndxPtr[0]=revDescIndxPtr[-1]+1;
1085 for(int j=commonCellsIPtr[0];j<commonCellsIPtr[1];j++)
1086 revDesc->pushBackSilent(revDesc2Ptr[commonCellsPtr[j]]);
1087 revDescIndxPtr[0]=revDescIndxPtr[-1]+commonCellsIPtr[1]-commonCellsIPtr[0];
1095 struct MEDCouplingAccVisit
1097 MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1098 int operator()(int val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1099 int _new_nb_of_nodes;
1105 * Converts specified cells to either polygons (if \a this is a 2D mesh) or
1106 * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an
1107 * array of cell ids. Pay attention that after conversion all algorithms work slower
1108 * with \a this mesh than before conversion. <br> If an exception is thrown during the
1109 * conversion due presence of invalid ids in the array of cells to convert, as a
1110 * result \a this mesh contains some already converted elements. In this case the 2D
1111 * mesh remains valid but 3D mesh becomes \b inconsistent!
1112 * \warning This method can significantly modify the order of geometric types in \a this,
1113 * hence, to write this mesh to the MED file, its cells must be sorted using
1114 * sortCellsInMEDFileFrmt().
1115 * \param [in] cellIdsToConvertBg - the array holding ids of cells to convert.
1116 * \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a
1117 * cellIdsToConvertBg.
1118 * \throw If the coordinates array is not set.
1119 * \throw If the nodal connectivity of cells is node defined.
1120 * \throw If dimension of \a this mesh is not either 2 or 3.
1122 * \if ENABLE_EXAMPLES
1123 * \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".<br>
1124 * \ref py_mcumesh_convertToPolyTypes "Here is a Python example".
1127 void MEDCouplingUMesh::convertToPolyTypes(const int *cellIdsToConvertBg, const int *cellIdsToConvertEnd)
1129 checkFullyDefined();
1130 int dim=getMeshDimension();
1132 throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
1133 int nbOfCells(getNumberOfCells());
1136 const int *connIndex=_nodal_connec_index->getConstPointer();
1137 int *conn=_nodal_connec->getPointer();
1138 for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1140 if(*iter>=0 && *iter<nbOfCells)
1142 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
1143 if(!cm.isQuadratic())
1144 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
1146 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
1150 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1151 oss << " in range [0," << nbOfCells << ") !";
1152 throw INTERP_KERNEL::Exception(oss.str());
1158 int *connIndex(_nodal_connec_index->getPointer());
1159 const int *connOld(_nodal_connec->getConstPointer());
1160 MCAuto<DataArrayInt> connNew(DataArrayInt::New()),connNewI(DataArrayInt::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0);
1161 std::vector<bool> toBeDone(nbOfCells,false);
1162 for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1164 if(*iter>=0 && *iter<nbOfCells)
1165 toBeDone[*iter]=true;
1168 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1169 oss << " in range [0," << nbOfCells << ") !";
1170 throw INTERP_KERNEL::Exception(oss.str());
1173 for(int cellId=0;cellId<nbOfCells;cellId++)
1175 int pos(connIndex[cellId]),posP1(connIndex[cellId+1]);
1176 int lgthOld(posP1-pos-1);
1177 if(toBeDone[cellId])
1179 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connOld[pos]);
1180 unsigned nbOfFaces(cm.getNumberOfSons2(connOld+pos+1,lgthOld));
1181 int *tmp(new int[nbOfFaces*lgthOld+1]);
1182 int *work=tmp; *work++=INTERP_KERNEL::NORM_POLYHED;
1183 for(unsigned j=0;j<nbOfFaces;j++)
1185 INTERP_KERNEL::NormalizedCellType type;
1186 unsigned offset=cm.fillSonCellNodalConnectivity2(j,connOld+pos+1,lgthOld,work,type);
1190 std::size_t newLgth(std::distance(tmp,work)-1);//-1 for last -1
1191 connNew->pushBackValsSilent(tmp,tmp+newLgth);
1192 connNewI->pushBackSilent(connNewI->back()+(int)newLgth);
1197 connNew->pushBackValsSilent(connOld+pos,connOld+posP1);
1198 connNewI->pushBackSilent(connNewI->back()+posP1-pos);
1201 setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind.
1207 * Converts all cells to either polygons (if \a this is a 2D mesh) or
1208 * polyhedrons (if \a this is a 3D mesh).
1209 * \warning As this method is purely for user-friendliness and no optimization is
1210 * done to avoid construction of a useless vector, this method can be costly
1212 * \throw If the coordinates array is not set.
1213 * \throw If the nodal connectivity of cells is node defined.
1214 * \throw If dimension of \a this mesh is not either 2 or 3.
1216 void MEDCouplingUMesh::convertAllToPoly()
1218 int nbOfCells=getNumberOfCells();
1219 std::vector<int> cellIds(nbOfCells);
1220 for(int i=0;i<nbOfCells;i++)
1222 convertToPolyTypes(&cellIds[0],&cellIds[0]+cellIds.size());
1226 * Fixes nodal connectivity of invalid cells of type NORM_POLYHED. This method
1227 * expects that all NORM_POLYHED cells have connectivity similar to that of prismatic
1228 * volumes like NORM_HEXA8, NORM_PENTA6 etc., i.e. the first half of nodes describes a
1229 * base facet of the volume and the second half of nodes describes an opposite facet
1230 * having the same number of nodes as the base one. This method converts such
1231 * connectivity to a valid polyhedral format where connectivity of each facet is
1232 * explicitly described and connectivity of facets are separated by -1. If \a this mesh
1233 * contains a NORM_POLYHED cell with a valid connectivity, or an invalid connectivity is
1234 * not as expected, an exception is thrown and the mesh remains unchanged. Care of
1235 * a correct orientation of the first facet of a polyhedron, else orientation of a
1236 * corrected cell is reverse.<br>
1237 * This method is useful to build an extruded unstructured mesh with polyhedrons as
1238 * it releases the user from boring description of polyhedra connectivity in the valid
1240 * \throw If \a this->getMeshDimension() != 3.
1241 * \throw If \a this->getSpaceDimension() != 3.
1242 * \throw If the nodal connectivity of cells is not defined.
1243 * \throw If the coordinates array is not set.
1244 * \throw If \a this mesh contains polyhedrons with the valid connectivity.
1245 * \throw If \a this mesh contains polyhedrons with odd number of nodes.
1247 * \if ENABLE_EXAMPLES
1248 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
1249 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
1252 void MEDCouplingUMesh::convertExtrudedPolyhedra()
1254 checkFullyDefined();
1255 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1256 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
1257 int nbOfCells=getNumberOfCells();
1258 MCAuto<DataArrayInt> newCi=DataArrayInt::New();
1259 newCi->alloc(nbOfCells+1,1);
1260 int *newci=newCi->getPointer();
1261 const int *ci=_nodal_connec_index->getConstPointer();
1262 const int *c=_nodal_connec->getConstPointer();
1264 for(int i=0;i<nbOfCells;i++)
1266 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1267 if(type==INTERP_KERNEL::NORM_POLYHED)
1269 if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
1271 std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
1272 throw INTERP_KERNEL::Exception(oss.str());
1274 std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
1277 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 !";
1278 throw INTERP_KERNEL::Exception(oss.str());
1281 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)
1284 newci[i+1]=(ci[i+1]-ci[i])+newci[i];
1286 MCAuto<DataArrayInt> newC=DataArrayInt::New();
1287 newC->alloc(newci[nbOfCells],1);
1288 int *newc=newC->getPointer();
1289 for(int i=0;i<nbOfCells;i++)
1291 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1292 if(type==INTERP_KERNEL::NORM_POLYHED)
1294 std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
1295 newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
1297 for(std::size_t j=0;j<n1;j++)
1299 newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
1301 newc[n1+5*j+1]=c[ci[i]+1+j];
1302 newc[n1+5*j+2]=c[ci[i]+1+j+n1];
1303 newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
1304 newc[n1+5*j+4]=c[ci[i]+1+(j+1)%n1];
1309 newc=std::copy(c+ci[i],c+ci[i+1],newc);
1311 _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
1312 _nodal_connec->decrRef(); _nodal_connec=newC.retn();
1317 * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D
1318 * mesh) to cells of classical types. This method is opposite to convertToPolyTypes().
1319 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
1320 * to write this mesh to the MED file, its cells must be sorted using
1321 * sortCellsInMEDFileFrmt().
1322 * \warning Cells (and most notably polyhedrons) must be correctly oriented for this to work
1323 * properly. See orientCorrectlyPolyhedrons() and arePolyhedronsNotCorrectlyOriented().
1324 * \return \c true if at least one cell has been converted, \c false else. In the
1325 * last case the nodal connectivity remains unchanged.
1326 * \throw If the coordinates array is not set.
1327 * \throw If the nodal connectivity of cells is not defined.
1328 * \throw If \a this->getMeshDimension() < 0.
1330 bool MEDCouplingUMesh::unPolyze()
1332 checkFullyDefined();
1333 int mdim=getMeshDimension();
1335 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1338 int nbOfCells=getNumberOfCells();
1341 int initMeshLgth=getNodalConnectivityArrayLen();
1342 int *conn=_nodal_connec->getPointer();
1343 int *index=_nodal_connec_index->getPointer();
1348 for(int i=0;i<nbOfCells;i++)
1350 lgthOfCurCell=index[i+1]-posOfCurCell;
1351 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1352 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1353 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1357 switch(cm.getDimension())
1361 INTERP_KERNEL::AutoPtr<int> tmp=new int[lgthOfCurCell-1];
1362 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(int *)tmp);
1363 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1368 int nbOfFaces,lgthOfPolyhConn;
1369 INTERP_KERNEL::AutoPtr<int> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1370 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1375 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1379 ret=ret || (newType!=type);
1380 conn[newPos]=newType;
1382 posOfCurCell=index[i+1];
1387 std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1388 newPos+=lgthOfCurCell;
1389 posOfCurCell+=lgthOfCurCell;
1393 if(newPos!=initMeshLgth)
1394 _nodal_connec->reAlloc(newPos);
1401 * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1402 * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1403 * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells.
1405 * \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
1408 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1410 checkFullyDefined();
1411 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1412 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1413 MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1414 coords->recenterForMaxPrecision(eps);
1416 int nbOfCells=getNumberOfCells();
1417 const int *conn=_nodal_connec->getConstPointer();
1418 const int *index=_nodal_connec_index->getConstPointer();
1419 MCAuto<DataArrayInt> connINew=DataArrayInt::New();
1420 connINew->alloc(nbOfCells+1,1);
1421 int *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1422 MCAuto<DataArrayInt> connNew=DataArrayInt::New(); connNew->alloc(0,1);
1424 for(int i=0;i<nbOfCells;i++,connINewPtr++)
1426 if(conn[index[i]]==(int)INTERP_KERNEL::NORM_POLYHED)
1428 SimplifyPolyhedronCell(eps,coords,conn+index[i],conn+index[i+1],connNew);
1432 connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1433 *connINewPtr=connNew->getNumberOfTuples();
1436 setConnectivity(connNew,connINew,false);
1440 * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1441 * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1442 * the format of the returned DataArrayInt instance.
1444 * \return a newly allocated DataArrayInt sorted ascendingly of fetched node ids.
1445 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1447 DataArrayInt *MEDCouplingUMesh::computeFetchedNodeIds() const
1449 checkConnectivityFullyDefined();
1450 const int *maxEltPt(std::max_element(_nodal_connec->begin(),_nodal_connec->end()));
1451 int maxElt(maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1);
1452 std::vector<bool> retS(maxElt,false);
1453 computeNodeIdsAlg(retS);
1454 return DataArrayInt::BuildListOfSwitchedOn(retS);
1458 * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1459 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1461 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1463 int nbOfNodes((int)nodeIdsInUse.size()),nbOfCells(getNumberOfCells());
1464 const int *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1465 for(int i=0;i<nbOfCells;i++)
1466 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1469 if(conn[j]<nbOfNodes)
1470 nodeIdsInUse[conn[j]]=true;
1473 std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1474 throw INTERP_KERNEL::Exception(oss.str());
1480 * Finds nodes not used in any cell and returns an array giving a new id to every node
1481 * by excluding the unused nodes, for which the array holds -1. The result array is
1482 * a mapping in "Old to New" mode.
1483 * \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1484 * \return DataArrayInt * - a new instance of DataArrayInt. Its length is \a
1485 * this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1486 * if the node is unused or a new id else. The caller is to delete this
1487 * array using decrRef() as it is no more needed.
1488 * \throw If the coordinates array is not set.
1489 * \throw If the nodal connectivity of cells is not defined.
1490 * \throw If the nodal connectivity includes an invalid id.
1492 * \if ENABLE_EXAMPLES
1493 * \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1494 * \ref py_mcumesh_getNodeIdsInUse "Here is a Python example".
1496 * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1498 DataArrayInt *MEDCouplingUMesh::getNodeIdsInUse(int& nbrOfNodesInUse) const
1501 int nbOfNodes(getNumberOfNodes());
1502 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1503 ret->alloc(nbOfNodes,1);
1504 int *traducer=ret->getPointer();
1505 std::fill(traducer,traducer+nbOfNodes,-1);
1506 int nbOfCells=getNumberOfCells();
1507 const int *connIndex=_nodal_connec_index->getConstPointer();
1508 const int *conn=_nodal_connec->getConstPointer();
1509 for(int i=0;i<nbOfCells;i++)
1510 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1513 if(conn[j]<nbOfNodes)
1514 traducer[conn[j]]=1;
1517 std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1518 throw INTERP_KERNEL::Exception(oss.str());
1521 nbrOfNodesInUse=(int)std::count(traducer,traducer+nbOfNodes,1);
1522 std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1527 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1528 * For each cell in \b this the number of nodes constituting cell is computed.
1529 * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1530 * So for pohyhedrons some nodes can be counted several times in the returned result.
1532 * \return a newly allocated array
1533 * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1535 DataArrayInt *MEDCouplingUMesh::computeNbOfNodesPerCell() 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 if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1547 *retPtr=connI[i+1]-connI[i]-1;
1549 *retPtr=connI[i+1]-connI[i]-1-std::count(conn+connI[i]+1,conn+connI[i+1],-1);
1555 * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1556 * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1558 * \return DataArrayInt * - new object to be deallocated by the caller.
1559 * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1561 DataArrayInt *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1563 checkConnectivityFullyDefined();
1564 int nbOfCells=getNumberOfCells();
1565 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1566 ret->alloc(nbOfCells,1);
1567 int *retPtr=ret->getPointer();
1568 const int *conn=getNodalConnectivity()->getConstPointer();
1569 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1570 for(int i=0;i<nbOfCells;i++,retPtr++)
1572 std::set<int> s(conn+connI[i]+1,conn+connI[i+1]);
1573 if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1574 *retPtr=(int)s.size();
1578 *retPtr=(int)s.size();
1585 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1586 * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1588 * \return a newly allocated array
1590 DataArrayInt *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1592 checkConnectivityFullyDefined();
1593 int nbOfCells=getNumberOfCells();
1594 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1595 ret->alloc(nbOfCells,1);
1596 int *retPtr=ret->getPointer();
1597 const int *conn=getNodalConnectivity()->getConstPointer();
1598 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1599 for(int i=0;i<nbOfCells;i++,retPtr++,connI++)
1601 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1602 *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1608 * Removes unused nodes (the node coordinates array is shorten) and returns an array
1609 * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1610 * array mean that the corresponding old node is no more used.
1611 * \return DataArrayInt * - a new instance of DataArrayInt of length \a
1612 * this->getNumberOfNodes() before call of this method. The caller is to
1613 * delete this array using decrRef() as it is no more needed.
1614 * \throw If the coordinates array is not set.
1615 * \throw If the nodal connectivity of cells is not defined.
1616 * \throw If the nodal connectivity includes an invalid id.
1617 * \sa areAllNodesFetched
1619 * \if ENABLE_EXAMPLES
1620 * \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1621 * \ref py_mcumesh_zipCoordsTraducer "Here is a Python example".
1624 DataArrayInt *MEDCouplingUMesh::zipCoordsTraducer()
1626 return MEDCouplingPointSet::zipCoordsTraducer();
1630 * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1631 * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1633 int MEDCouplingUMesh::AreCellsEqual(const int *conn, const int *connI, int cell1, int cell2, int compType)
1638 return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1640 return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1642 return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1644 return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1646 return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1648 throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1652 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1654 int MEDCouplingUMesh::AreCellsEqualPolicy0(const int *conn, const int *connI, int cell1, int cell2)
1656 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1657 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1662 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1664 int MEDCouplingUMesh::AreCellsEqualPolicy1(const int *conn, const int *connI, int cell1, int cell2)
1666 int sz=connI[cell1+1]-connI[cell1];
1667 if(sz==connI[cell2+1]-connI[cell2])
1669 if(conn[connI[cell1]]==conn[connI[cell2]])
1671 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1672 unsigned dim=cm.getDimension();
1678 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1679 int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1680 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1681 work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1682 return work!=tmp+sz1?1:0;
1685 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1688 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1695 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1697 int MEDCouplingUMesh::AreCellsEqualPolicy2(const int *conn, const int *connI, int cell1, int cell2)
1699 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1701 if(conn[connI[cell1]]==conn[connI[cell2]])
1703 std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1704 std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1712 * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1714 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const int *conn, const int *connI, int cell1, int cell2)
1716 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1718 std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1719 std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1726 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1728 int MEDCouplingUMesh::AreCellsEqualPolicy7(const int *conn, const int *connI, int cell1, int cell2)
1730 int sz=connI[cell1+1]-connI[cell1];
1731 if(sz==connI[cell2+1]-connI[cell2])
1733 if(conn[connI[cell1]]==conn[connI[cell2]])
1735 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1736 unsigned dim=cm.getDimension();
1742 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1743 int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1744 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1745 work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1750 std::reverse_iterator<int *> it1((int *)tmp+sz1);
1751 std::reverse_iterator<int *> it2((int *)tmp);
1752 if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1758 return work!=tmp+sz1?1:0;
1761 {//case of SEG2 and SEG3
1762 if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1764 if(!cm.isQuadratic())
1766 std::reverse_iterator<const int *> it1(conn+connI[cell1+1]);
1767 std::reverse_iterator<const int *> it2(conn+connI[cell1]+1);
1768 if(std::equal(it1,it2,conn+connI[cell2]+1))
1774 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])
1781 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1788 * This method find in candidate pool defined by 'candidates' the cells equal following the polycy 'compType'.
1789 * If any true is returned and the results will be put at the end of 'result' output parameter. If not false is returned
1790 * and result remains unchanged.
1791 * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1792 * If in 'candidates' pool -1 value is considered as an empty value.
1793 * WARNING this method returns only ONE set of result !
1795 bool MEDCouplingUMesh::AreCellsEqualInPool(const std::vector<int>& candidates, int compType, const int *conn, const int *connI, DataArrayInt *result)
1797 if(candidates.size()<1)
1800 std::vector<int>::const_iterator iter=candidates.begin();
1801 int start=(*iter++);
1802 for(;iter!=candidates.end();iter++)
1804 int status=AreCellsEqual(conn,connI,start,*iter,compType);
1809 result->pushBackSilent(start);
1813 result->pushBackSilent(*iter);
1815 result->pushBackSilent(status==2?(*iter+1):-(*iter+1));
1822 * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified
1824 * This method keeps the coordiantes of \a this. This method is time consuming.
1826 * \param [in] compType input specifying the technique used to compare cells each other.
1827 * - 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.
1828 * - 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)
1829 * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1830 * - 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
1831 * can be used for users not sensitive to orientation of cell
1832 * \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.
1833 * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1834 * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1835 * \return the correspondance array old to new in a newly allocated array.
1838 void MEDCouplingUMesh::findCommonCells(int compType, int startCellId, DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr) const
1840 MCAuto<DataArrayInt> revNodal=DataArrayInt::New(),revNodalI=DataArrayInt::New();
1841 getReverseNodalConnectivity(revNodal,revNodalI);
1842 FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1845 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, int startCellId, const DataArrayInt *nodal, const DataArrayInt *nodalI, const DataArrayInt *revNodal, const DataArrayInt *revNodalI,
1846 DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr)
1848 MCAuto<DataArrayInt> commonCells=DataArrayInt::New(),commonCellsI=DataArrayInt::New(); commonCells->alloc(0,1);
1849 int nbOfCells=nodalI->getNumberOfTuples()-1;
1850 commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1851 const int *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1852 const int *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1853 std::vector<bool> isFetched(nbOfCells,false);
1856 for(int i=0;i<nbOfCells;i++)
1860 const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1861 std::vector<int> v,v2;
1862 if(connOfNode!=connPtr+connIPtr[i+1])
1864 const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1865 v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1868 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1872 const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1873 std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1874 v2.resize(std::distance(v2.begin(),it));
1878 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1880 int pos=commonCellsI->back();
1881 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1882 for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1883 isFetched[*it]=true;
1891 for(int i=startCellId;i<nbOfCells;i++)
1895 const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1896 std::vector<int> v,v2;
1897 if(connOfNode!=connPtr+connIPtr[i+1])
1899 v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1902 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1906 std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1907 v2.resize(std::distance(v2.begin(),it));
1911 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1913 int pos=commonCellsI->back();
1914 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1915 for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1916 isFetched[*it]=true;
1922 commonCellsArr=commonCells.retn();
1923 commonCellsIArr=commonCellsI.retn();
1927 * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1928 * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1929 * than \a this->getNumberOfCells() in the returned array means that there is no
1930 * corresponding cell in \a this mesh.
1931 * It is expected that \a this and \a other meshes share the same node coordinates
1932 * array, if it is not so an exception is thrown.
1933 * \param [in] other - the mesh to compare with.
1934 * \param [in] compType - specifies a cell comparison technique. For meaning of its
1935 * valid values [0,1,2], see zipConnectivityTraducer().
1936 * \param [out] arr - a new instance of DataArrayInt returning correspondence
1937 * between cells of the two meshes. It contains \a other->getNumberOfCells()
1938 * values. The caller is to delete this array using
1939 * decrRef() as it is no more needed.
1940 * \return bool - \c true if all cells of \a other mesh are present in the \a this
1943 * \if ENABLE_EXAMPLES
1944 * \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1945 * \ref py_mcumesh_areCellsIncludedIn "Here is a Python example".
1947 * \sa checkDeepEquivalOnSameNodesWith()
1948 * \sa checkGeoEquivalWith()
1950 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayInt *& arr) const
1952 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1953 int nbOfCells=getNumberOfCells();
1954 static const int possibleCompType[]={0,1,2};
1955 if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1957 std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1958 std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1960 throw INTERP_KERNEL::Exception(oss.str());
1962 MCAuto<DataArrayInt> o2n=mesh->zipConnectivityTraducer(compType,nbOfCells);
1963 arr=o2n->subArray(nbOfCells);
1964 arr->setName(other->getName());
1966 if(other->getNumberOfCells()==0)
1968 return arr->getMaxValue(tmp)<nbOfCells;
1972 * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1973 * This method tries to determine if \b other is fully included in \b this.
1974 * The main difference is that this method is not expected to throw exception.
1975 * This method has two outputs :
1977 * \param other other mesh
1978 * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1979 * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
1981 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayInt *& arr) const
1983 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1984 DataArrayInt *commonCells=0,*commonCellsI=0;
1985 int thisNbCells=getNumberOfCells();
1986 mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
1987 MCAuto<DataArrayInt> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1988 const int *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
1989 int otherNbCells=other->getNumberOfCells();
1990 MCAuto<DataArrayInt> arr2=DataArrayInt::New();
1991 arr2->alloc(otherNbCells,1);
1992 arr2->fillWithZero();
1993 int *arr2Ptr=arr2->getPointer();
1994 int nbOfCommon=commonCellsI->getNumberOfTuples()-1;
1995 for(int i=0;i<nbOfCommon;i++)
1997 int start=commonCellsPtr[commonCellsIPtr[i]];
1998 if(start<thisNbCells)
2000 for(int j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
2002 int sig=commonCellsPtr[j]>0?1:-1;
2003 int val=std::abs(commonCellsPtr[j])-1;
2004 if(val>=thisNbCells)
2005 arr2Ptr[val-thisNbCells]=sig*(start+1);
2009 arr2->setName(other->getName());
2010 if(arr2->presenceOfValue(0))
2016 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
2019 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
2020 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
2022 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
2023 std::vector<const MEDCouplingUMesh *> ms(2);
2026 return MergeUMeshesOnSameCoords(ms);
2030 * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
2031 * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
2032 * cellIds is not given explicitely but by a range python like.
2037 * \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.
2038 * \return a newly allocated
2040 * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
2041 * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
2043 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(int start, int end, int step, bool keepCoords) const
2045 if(getMeshDimension()!=-1)
2046 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
2049 int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
2051 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2053 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2055 return const_cast<MEDCouplingUMesh *>(this);
2060 * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
2061 * The result mesh shares or not the node coordinates array with \a this mesh depending
2062 * on \a keepCoords parameter.
2063 * \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
2064 * to write this mesh to the MED file, its cells must be sorted using
2065 * sortCellsInMEDFileFrmt().
2066 * \param [in] begin - an array of cell ids to include to the new mesh.
2067 * \param [in] end - a pointer to last-plus-one-th element of \a begin.
2068 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2069 * array of \a this mesh, else "free" nodes are removed from the result mesh
2070 * by calling zipCoords().
2071 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2072 * to delete this mesh using decrRef() as it is no more needed.
2073 * \throw If the coordinates array is not set.
2074 * \throw If the nodal connectivity of cells is not defined.
2075 * \throw If any cell id in the array \a begin is not valid.
2077 * \if ENABLE_EXAMPLES
2078 * \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
2079 * \ref py_mcumesh_buildPartOfMySelf "Here is a Python example".
2082 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const int *begin, const int *end, bool keepCoords) const
2084 if(getMeshDimension()!=-1)
2085 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
2089 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2091 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2093 return const_cast<MEDCouplingUMesh *>(this);
2098 * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
2100 * 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.
2101 * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
2102 * The number of cells of \b this will remain the same with this method.
2104 * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
2105 * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
2106 * \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 ).
2107 * Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
2109 void MEDCouplingUMesh::setPartOfMySelf(const int *cellIdsBg, const int *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2111 checkConnectivityFullyDefined();
2112 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2113 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2114 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2115 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2117 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2118 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2119 throw INTERP_KERNEL::Exception(oss.str());
2121 int nbOfCellsToModify=(int)std::distance(cellIdsBg,cellIdsEnd);
2122 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2124 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2125 throw INTERP_KERNEL::Exception(oss.str());
2127 int nbOfCells=getNumberOfCells();
2128 bool easyAssign=true;
2129 const int *connI=_nodal_connec_index->getConstPointer();
2130 const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2131 for(const int *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2133 if(*it>=0 && *it<nbOfCells)
2135 easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2139 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2140 throw INTERP_KERNEL::Exception(oss.str());
2145 MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2150 DataArrayInt *arrOut=0,*arrIOut=0;
2151 MEDCouplingUMesh::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2153 MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2154 setConnectivity(arrOut,arrIOut,true);
2158 void MEDCouplingUMesh::setPartOfMySelfSlice(int start, int end, int step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2160 checkConnectivityFullyDefined();
2161 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2162 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2163 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2164 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2166 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2167 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2168 throw INTERP_KERNEL::Exception(oss.str());
2170 int nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2171 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2173 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2174 throw INTERP_KERNEL::Exception(oss.str());
2176 int nbOfCells=getNumberOfCells();
2177 bool easyAssign=true;
2178 const int *connI=_nodal_connec_index->getConstPointer();
2179 const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2181 for(int i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2183 if(it>=0 && it<nbOfCells)
2185 easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2189 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2190 throw INTERP_KERNEL::Exception(oss.str());
2195 MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2200 DataArrayInt *arrOut=0,*arrIOut=0;
2201 MEDCouplingUMesh::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2203 MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2204 setConnectivity(arrOut,arrIOut,true);
2209 * Keeps from \a this only cells which constituing point id are in the ids specified by [ \a begin,\a end ).
2210 * The resulting cell ids are stored at the end of the 'cellIdsKept' parameter.
2211 * Parameter \a fullyIn specifies if a cell that has part of its nodes in ids array is kept or not.
2212 * If \a fullyIn is true only cells whose ids are \b fully contained in [ \a begin,\a end ) tab will be kept.
2214 * \param [in] begin input start of array of node ids.
2215 * \param [in] end input end of array of node ids.
2216 * \param [in] fullyIn input that specifies if all node ids must be in [ \a begin,\a end ) array to consider cell to be in.
2217 * \param [in,out] cellIdsKeptArr array where all candidate cell ids are put at the end.
2219 void MEDCouplingUMesh::fillCellIdsToKeepFromNodeIds(const int *begin, const int *end, bool fullyIn, DataArrayInt *&cellIdsKeptArr) const
2221 MCAuto<DataArrayInt> cellIdsKept=DataArrayInt::New(); cellIdsKept->alloc(0,1);
2222 checkConnectivityFullyDefined();
2224 int sz=getNodalConnectivity()->getMaxValue(tmp); sz=std::max(sz,0)+1;
2225 std::vector<bool> fastFinder(sz,false);
2226 for(const int *work=begin;work!=end;work++)
2227 if(*work>=0 && *work<sz)
2228 fastFinder[*work]=true;
2229 int nbOfCells=getNumberOfCells();
2230 const int *conn=getNodalConnectivity()->getConstPointer();
2231 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2232 for(int i=0;i<nbOfCells;i++)
2234 int ref=0,nbOfHit=0;
2235 for(const int *work2=conn+connIndex[i]+1;work2!=conn+connIndex[i+1];work2++)
2239 if(fastFinder[*work2])
2242 if((ref==nbOfHit && fullyIn) || (nbOfHit!=0 && !fullyIn))
2243 cellIdsKept->pushBackSilent(i);
2245 cellIdsKeptArr=cellIdsKept.retn();
2249 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2250 * this->getMeshDimension(), that bound some cells of \a this mesh.
2251 * The cells of lower dimension to include to the result mesh are selected basing on
2252 * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2253 * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2254 * ==\c false, a cell is copied if any its node is in the array of node ids. The
2255 * created mesh shares the node coordinates array with \a this mesh.
2256 * \param [in] begin - the array of node ids.
2257 * \param [in] end - a pointer to the (last+1)-th element of \a begin.
2258 * \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2259 * array \a begin are added, else cells whose any node is in the
2260 * array \a begin are added.
2261 * \return MEDCouplingUMesh * - 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.
2265 * \throw If any node id in \a begin is not valid.
2267 * \if ENABLE_EXAMPLES
2268 * \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2269 * \ref py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2272 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const int *begin, const int *end, bool fullyIn) const
2274 MCAuto<DataArrayInt> desc,descIndx,revDesc,revDescIndx;
2275 desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=DataArrayInt::New(); revDescIndx=DataArrayInt::New();
2276 MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2277 desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2278 return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2282 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2283 * this->getMeshDimension(), which bound only one cell of \a this mesh.
2284 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2285 * array of \a this mesh, else "free" nodes are removed from the result mesh
2286 * by calling zipCoords().
2287 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2288 * to delete this mesh using decrRef() as it is no more needed.
2289 * \throw If the coordinates array is not set.
2290 * \throw If the nodal connectivity of cells is not defined.
2292 * \if ENABLE_EXAMPLES
2293 * \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2294 * \ref py_mcumesh_buildBoundaryMesh "Here is a Python example".
2297 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2299 DataArrayInt *desc=DataArrayInt::New();
2300 DataArrayInt *descIndx=DataArrayInt::New();
2301 DataArrayInt *revDesc=DataArrayInt::New();
2302 DataArrayInt *revDescIndx=DataArrayInt::New();
2304 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2307 descIndx->decrRef();
2308 int nbOfCells=meshDM1->getNumberOfCells();
2309 const int *revDescIndxC=revDescIndx->getConstPointer();
2310 std::vector<int> boundaryCells;
2311 for(int i=0;i<nbOfCells;i++)
2312 if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2313 boundaryCells.push_back(i);
2314 revDescIndx->decrRef();
2315 MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2320 * This method returns a newly created DataArrayInt instance containing ids of cells located in boundary.
2321 * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2322 * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2324 DataArrayInt *MEDCouplingUMesh::findCellIdsOnBoundary() const
2326 checkFullyDefined();
2327 MCAuto<DataArrayInt> desc=DataArrayInt::New();
2328 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2329 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2330 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2332 buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2333 desc=(DataArrayInt*)0; descIndx=(DataArrayInt*)0;
2335 MCAuto<DataArrayInt> tmp=revDescIndx->deltaShiftIndex();
2336 MCAuto<DataArrayInt> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayInt*)0;
2337 const int *revDescPtr=revDesc->getConstPointer();
2338 const int *revDescIndxPtr=revDescIndx->getConstPointer();
2339 int nbOfCells=getNumberOfCells();
2340 std::vector<bool> ret1(nbOfCells,false);
2342 for(const int *pt=faceIds->begin();pt!=faceIds->end();pt++)
2343 if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2344 { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2346 DataArrayInt *ret2=DataArrayInt::New();
2348 int *ret2Ptr=ret2->getPointer();
2350 for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2353 ret2->setName("BoundaryCells");
2358 * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2359 * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2360 * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2361 * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2363 * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2364 * 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
2365 * equals a cell in \b otherDimM1OnSameCoords.
2367 * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2368 * are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2370 * \param [in] otherDimM1OnSameCoords
2371 * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2372 * \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
2373 * cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2375 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *&cellIdsRk0, DataArrayInt *&cellIdsRk1) const
2377 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2378 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2379 checkConnectivityFullyDefined();
2380 otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2381 if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2382 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2383 MCAuto<DataArrayInt> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2384 MCAuto<DataArrayInt> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2385 MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2386 MCAuto<DataArrayInt> descThisPart=DataArrayInt::New(),descIThisPart=DataArrayInt::New(),revDescThisPart=DataArrayInt::New(),revDescIThisPart=DataArrayInt::New();
2387 MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2388 const int *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2389 DataArrayInt *idsOtherInConsti=0;
2390 bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2391 MCAuto<DataArrayInt> idsOtherInConstiAuto(idsOtherInConsti);
2393 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2395 for(const int *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2396 s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2397 MCAuto<DataArrayInt> s1arr_renum1=DataArrayInt::New(); s1arr_renum1->alloc((int)s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2398 s1arr_renum1->sort();
2399 cellIdsRk0=s0arr.retn();
2400 //cellIdsRk1=s_renum1.retn();
2401 cellIdsRk1=s1arr_renum1.retn();
2405 * 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
2406 * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2408 * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2410 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2412 MCAuto<DataArrayInt> desc=DataArrayInt::New();
2413 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2414 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2415 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2417 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2418 revDesc=0; desc=0; descIndx=0;
2419 MCAuto<DataArrayInt> revDescIndx2=revDescIndx->deltaShiftIndex();
2420 MCAuto<DataArrayInt> part=revDescIndx2->findIdsEqual(1);
2421 return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2425 * Finds nodes lying on the boundary of \a this mesh.
2426 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of found
2427 * nodes. The caller is to delete this array using decrRef() as it is no
2429 * \throw If the coordinates array is not set.
2430 * \throw If the nodal connectivity of cells is node defined.
2432 * \if ENABLE_EXAMPLES
2433 * \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2434 * \ref py_mcumesh_findBoundaryNodes "Here is a Python example".
2437 DataArrayInt *MEDCouplingUMesh::findBoundaryNodes() const
2439 MCAuto<MEDCouplingUMesh> skin=computeSkin();
2440 return skin->computeFetchedNodeIds();
2443 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2446 return const_cast<MEDCouplingUMesh *>(this);
2450 * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2451 * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2452 * 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.
2453 * 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.
2454 * 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.
2456 * \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
2457 * parameter is altered during the call.
2458 * \param [out] nodeIdsToDuplicate node ids needed to be duplicated following the algorithm explain above.
2459 * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2460 * \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.
2462 * \warning This method modifies param \b otherDimM1OnSameCoords (for speed reasons).
2464 void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *& nodeIdsToDuplicate,
2465 DataArrayInt *& cellIdsNeededToBeRenum, DataArrayInt *& cellIdsNotModified) const
2467 typedef MCAuto<DataArrayInt> DAInt;
2468 typedef MCAuto<MEDCouplingUMesh> MCUMesh;
2470 checkFullyDefined();
2471 otherDimM1OnSameCoords.checkFullyDefined();
2472 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2473 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2474 if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2475 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2477 // Checking star-shaped M1 group:
2478 DAInt dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2479 MCUMesh meshM2 = otherDimM1OnSameCoords.buildDescendingConnectivity(dt0, dit0, rdt0, rdit0);
2480 DAInt dsi = rdit0->deltaShiftIndex();
2481 DAInt idsTmp0 = dsi->findIdsNotInRange(-1, 3);
2482 if(idsTmp0->getNumberOfTuples())
2483 throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2484 dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2486 // Get extreme nodes from the group (they won't be duplicated), ie nodes belonging to boundary cells of M1
2487 DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2488 MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2489 DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2490 // Remove from the list points on the boundary of the M0 mesh (those need duplication!)
2491 dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2492 MCUMesh m0desc = buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0;
2493 dsi = rdit0->deltaShiftIndex();
2494 DAInt boundSegs = dsi->findIdsEqual(1); // boundary segs/faces of the M0 mesh
2495 MCUMesh m0descSkin = static_cast<MEDCouplingUMesh *>(m0desc->buildPartOfMySelf(boundSegs->begin(),boundSegs->end(), true));
2496 DAInt fNodes = m0descSkin->computeFetchedNodeIds();
2497 // In 3D, some points on the boundary of M0 still need duplication:
2499 if (getMeshDimension() == 3)
2501 DAInt dnu1=DataArrayInt::New(), dnu2=DataArrayInt::New(), dnu3=DataArrayInt::New(), dnu4=DataArrayInt::New();
2502 MCUMesh m0descSkinDesc = m0descSkin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4);
2503 dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2504 DataArrayInt * corresp=0;
2505 meshM2->areCellsIncludedIn(m0descSkinDesc,2,corresp);
2506 DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2508 if (validIds->getNumberOfTuples())
2510 MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0descSkinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2511 DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2512 DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2513 notDup = xtrem->buildSubstraction(fNodes1);
2516 notDup = xtrem->buildSubstraction(fNodes);
2519 notDup = xtrem->buildSubstraction(fNodes);
2521 // Now compute cells around group (i.e. cells where we will do the propagation to identify the two sub-sets delimited by the group)
2522 DAInt m1Nodes = otherDimM1OnSameCoords.computeFetchedNodeIds();
2523 DAInt dupl = m1Nodes->buildSubstraction(notDup);
2524 DAInt cellsAroundGroup = getCellIdsLyingOnNodes(dupl->begin(), dupl->end(), false); // false= take cell in, even if not all nodes are in notDup
2527 MCUMesh m0Part2=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroup->begin(),cellsAroundGroup->end(),true));
2528 int nCells2 = m0Part2->getNumberOfCells();
2529 DAInt desc00=DataArrayInt::New(),descI00=DataArrayInt::New(),revDesc00=DataArrayInt::New(),revDescI00=DataArrayInt::New();
2530 MCUMesh m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00);
2532 // Neighbor information of the mesh without considering the crack (serves to count how many connex pieces it is made of)
2533 DataArrayInt *tmp00=0,*tmp11=0;
2534 MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00, tmp00, tmp11);
2535 DAInt neighInit00(tmp00);
2536 DAInt neighIInit00(tmp11);
2537 // Neighbor information of the mesh WITH the crack (some neighbors are removed):
2538 DataArrayInt *idsTmp=0;
2539 bool b=m01->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsTmp);
2541 // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2542 // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2543 MEDCouplingUMesh::RemoveIdsFromIndexedArrays(ids->begin(),ids->end(),desc00,descI00);
2544 DataArrayInt *tmp0=0,*tmp1=0;
2545 // Compute the neighbor of each cell in m0Part2, taking into account the broken link above. Two
2546 // cells on either side of the crack (defined by the mesh of low dimension) are not neighbor anymore.
2547 ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00,tmp0,tmp1);
2548 DAInt neigh00(tmp0);
2549 DAInt neighI00(tmp1);
2551 // For each initial connex part of the sub-mesh (or said differently for each independent crack):
2552 int seed = 0, nIter = 0;
2553 int nIterMax = nCells2+1; // Safety net for the loop
2554 DAInt hitCells = DataArrayInt::New(); hitCells->alloc(nCells2);
2555 hitCells->fillWithValue(-1);
2556 DAInt cellsToModifyConn0_torenum = DataArrayInt::New();
2557 cellsToModifyConn0_torenum->alloc(0,1);
2558 while (nIter < nIterMax)
2560 DAInt t = hitCells->findIdsEqual(-1);
2561 if (!t->getNumberOfTuples())
2563 // Connex zone without the crack (to compute the next seed really)
2565 DAInt connexCheck = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neighInit00,neighIInit00, -1, dnu);
2567 for (int * ptr = connexCheck->getPointer(); cnt < connexCheck->getNumberOfTuples(); ptr++, cnt++)
2568 hitCells->setIJ(*ptr,0,1);
2569 // Connex zone WITH the crack (to identify cells lying on either part of the crack)
2570 DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neigh00,neighI00, -1, dnu);
2571 cellsToModifyConn0_torenum = DataArrayInt::Aggregate(cellsToModifyConn0_torenum, spreadZone, 0);
2572 // Compute next seed, i.e. a cell in another connex part, which was not covered by the previous iterations
2573 DAInt comple = cellsToModifyConn0_torenum->buildComplement(nCells2);
2574 DAInt nonHitCells = hitCells->findIdsEqual(-1);
2575 DAInt intersec = nonHitCells->buildIntersection(comple);
2576 if (intersec->getNumberOfTuples())
2577 { seed = intersec->getIJ(0,0); }
2582 if (nIter >= nIterMax)
2583 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate(): internal error - too many iterations.");
2585 DAInt cellsToModifyConn1_torenum=cellsToModifyConn0_torenum->buildComplement(neighI00->getNumberOfTuples()-1);
2586 cellsToModifyConn0_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2587 cellsToModifyConn1_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2589 cellIdsNeededToBeRenum=cellsToModifyConn0_torenum.retn();
2590 cellIdsNotModified=cellsToModifyConn1_torenum.retn();
2591 nodeIdsToDuplicate=dupl.retn();
2595 * This method operates a modification of the connectivity and coords in \b this.
2596 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2597 * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2598 * 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
2599 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2600 * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2602 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2604 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2605 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2607 void MEDCouplingUMesh::duplicateNodes(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd)
2609 int nbOfNodes=getNumberOfNodes();
2610 duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2611 duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2615 * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2616 * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2618 * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2620 * \sa renumberNodesInConn
2622 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(int offset)
2624 checkConnectivityFullyDefined();
2625 int *conn(getNodalConnectivity()->getPointer());
2626 const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2627 int nbOfCells(getNumberOfCells());
2628 for(int i=0;i<nbOfCells;i++)
2629 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2631 int& node=conn[iconn];
2632 if(node>=0)//avoid polyhedron separator
2637 _nodal_connec->declareAsNew();
2642 * Same than renumberNodesInConn(const int *) except that here the format of old-to-new traducer is using map instead
2643 * 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
2646 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<int,int>& newNodeNumbersO2N)
2648 checkConnectivityFullyDefined();
2649 int *conn(getNodalConnectivity()->getPointer());
2650 const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2651 int nbOfCells(getNumberOfCells());
2652 for(int i=0;i<nbOfCells;i++)
2653 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2655 int& node=conn[iconn];
2656 if(node>=0)//avoid polyhedron separator
2658 INTERP_KERNEL::HashMap<int,int>::const_iterator it(newNodeNumbersO2N.find(node));
2659 if(it!=newNodeNumbersO2N.end())
2665 std::ostringstream oss; oss << "MEDCouplingUMesh::renumberNodesInConn(map) : presence in connectivity for cell #" << i << " of node #" << node << " : Not in map !";
2666 throw INTERP_KERNEL::Exception(oss.str());
2670 _nodal_connec->declareAsNew();
2675 * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2676 * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2677 * This method is a generalization of shiftNodeNumbersInConn().
2678 * \warning This method performs no check of validity of new ids. **Use it with care !**
2679 * \param [in] newNodeNumbersO2N - a permutation array, of length \a
2680 * this->getNumberOfNodes(), in "Old to New" mode.
2681 * See \ref numbering for more info on renumbering modes.
2682 * \throw If the nodal connectivity of cells is not defined.
2684 * \if ENABLE_EXAMPLES
2685 * \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2686 * \ref py_mcumesh_renumberNodesInConn "Here is a Python example".
2689 void MEDCouplingUMesh::renumberNodesInConn(const int *newNodeNumbersO2N)
2691 checkConnectivityFullyDefined();
2692 int *conn=getNodalConnectivity()->getPointer();
2693 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2694 int nbOfCells(getNumberOfCells());
2695 for(int i=0;i<nbOfCells;i++)
2696 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2698 int& node=conn[iconn];
2699 if(node>=0)//avoid polyhedron separator
2701 node=newNodeNumbersO2N[node];
2704 _nodal_connec->declareAsNew();
2709 * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2710 * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2711 * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2713 * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2715 void MEDCouplingUMesh::shiftNodeNumbersInConn(int delta)
2717 checkConnectivityFullyDefined();
2718 int *conn=getNodalConnectivity()->getPointer();
2719 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2720 int nbOfCells=getNumberOfCells();
2721 for(int i=0;i<nbOfCells;i++)
2722 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2724 int& node=conn[iconn];
2725 if(node>=0)//avoid polyhedron separator
2730 _nodal_connec->declareAsNew();
2735 * This method operates a modification of the connectivity in \b this.
2736 * 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.
2737 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2738 * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2739 * 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
2740 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2741 * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2743 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2744 * As an another consequense after the call of this method \b this can be transiently non cohrent.
2746 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2747 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2748 * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ).
2750 void MEDCouplingUMesh::duplicateNodesInConn(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd, int offset)
2752 checkConnectivityFullyDefined();
2753 std::map<int,int> m;
2755 for(const int *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2757 int *conn=getNodalConnectivity()->getPointer();
2758 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2759 int nbOfCells=getNumberOfCells();
2760 for(int i=0;i<nbOfCells;i++)
2761 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2763 int& node=conn[iconn];
2764 if(node>=0)//avoid polyhedron separator
2766 std::map<int,int>::iterator it=m.find(node);
2775 * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2777 * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2778 * After the call of this method the number of cells remains the same as before.
2780 * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2781 * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2782 * be strictly in [0;this->getNumberOfCells()).
2784 * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2785 * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2786 * should be contained in[0;this->getNumberOfCells()).
2788 * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2791 void MEDCouplingUMesh::renumberCells(const int *old2NewBg, bool check)
2793 checkConnectivityFullyDefined();
2794 int nbCells=getNumberOfCells();
2795 const int *array=old2NewBg;
2797 array=DataArrayInt::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2799 const int *conn=_nodal_connec->getConstPointer();
2800 const int *connI=_nodal_connec_index->getConstPointer();
2801 MCAuto<DataArrayInt> o2n=DataArrayInt::New(); o2n->useArray(array,false,C_DEALLOC,nbCells,1);
2802 MCAuto<DataArrayInt> n2o=o2n->invertArrayO2N2N2O(nbCells);
2803 const int *n2oPtr=n2o->begin();
2804 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
2805 newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2806 newConn->copyStringInfoFrom(*_nodal_connec);
2807 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
2808 newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2809 newConnI->copyStringInfoFrom(*_nodal_connec_index);
2811 int *newC=newConn->getPointer();
2812 int *newCI=newConnI->getPointer();
2815 for(int i=0;i<nbCells;i++)
2818 int nbOfElts=connI[pos+1]-connI[pos];
2819 newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2824 setConnectivity(newConn,newConnI);
2826 free(const_cast<int *>(array));
2830 * Finds cells whose bounding boxes intersect a given bounding box.
2831 * \param [in] bbox - an array defining the bounding box via coordinates of its
2832 * extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2834 * \param [in] eps - a factor used to increase size of the bounding box of cell
2835 * before comparing it with \a bbox. This factor is multiplied by the maximal
2836 * extent of the bounding box of cell to produce an addition to this bounding box.
2837 * \return DataArrayInt * - a new instance of DataArrayInt holding ids for found
2838 * cells. The caller is to delete this array using decrRef() as it is no more
2840 * \throw If the coordinates array is not set.
2841 * \throw If the nodal connectivity of cells is not defined.
2843 * \if ENABLE_EXAMPLES
2844 * \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2845 * \ref py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2848 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2850 MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2851 if(getMeshDimension()==-1)
2853 elems->pushBackSilent(0);
2854 return elems.retn();
2856 int dim=getSpaceDimension();
2857 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2858 const int* conn = getNodalConnectivity()->getConstPointer();
2859 const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2860 const double* coords = getCoords()->getConstPointer();
2861 int nbOfCells=getNumberOfCells();
2862 for ( int ielem=0; ielem<nbOfCells;ielem++ )
2864 for (int i=0; i<dim; i++)
2866 elem_bb[i*2]=std::numeric_limits<double>::max();
2867 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2870 for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2872 int node= conn[inode];
2873 if(node>=0)//avoid polyhedron separator
2875 for (int idim=0; idim<dim; idim++)
2877 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2879 elem_bb[idim*2] = coords[node*dim+idim] ;
2881 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2883 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2888 if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2889 elems->pushBackSilent(ielem);
2891 return elems.retn();
2895 * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2896 * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2897 * added in 'elems' parameter.
2899 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2901 MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2902 if(getMeshDimension()==-1)
2904 elems->pushBackSilent(0);
2905 return elems.retn();
2907 int dim=getSpaceDimension();
2908 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2909 const int* conn = getNodalConnectivity()->getConstPointer();
2910 const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2911 const double* coords = getCoords()->getConstPointer();
2912 int nbOfCells=getNumberOfCells();
2913 for ( int ielem=0; ielem<nbOfCells;ielem++ )
2915 for (int i=0; i<dim; i++)
2917 elem_bb[i*2]=std::numeric_limits<double>::max();
2918 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2921 for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2923 int node= conn[inode];
2924 if(node>=0)//avoid polyhedron separator
2926 for (int idim=0; idim<dim; idim++)
2928 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2930 elem_bb[idim*2] = coords[node*dim+idim] ;
2932 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2934 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2939 if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
2940 elems->pushBackSilent(ielem);
2942 return elems.retn();
2946 * Returns a type of a cell by its id.
2947 * \param [in] cellId - the id of the cell of interest.
2948 * \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
2949 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2951 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(int cellId) const
2953 const int *ptI=_nodal_connec_index->getConstPointer();
2954 const int *pt=_nodal_connec->getConstPointer();
2955 if(cellId>=0 && cellId<(int)_nodal_connec_index->getNbOfElems()-1)
2956 return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2959 std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2960 throw INTERP_KERNEL::Exception(oss.str());
2965 * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2966 * This method does not throw exception if geometric type \a type is not in \a this.
2967 * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2968 * The coordinates array is not considered here.
2970 * \param [in] type the geometric type
2971 * \return cell ids in this having geometric type \a type.
2973 DataArrayInt *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2976 MCAuto<DataArrayInt> ret=DataArrayInt::New();
2978 checkConnectivityFullyDefined();
2979 int nbCells=getNumberOfCells();
2980 int mdim=getMeshDimension();
2981 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
2982 if(mdim!=(int)cm.getDimension())
2983 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
2984 const int *ptI=_nodal_connec_index->getConstPointer();
2985 const int *pt=_nodal_connec->getConstPointer();
2986 for(int i=0;i<nbCells;i++)
2988 if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
2989 ret->pushBackSilent(i);
2995 * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
2997 int MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2999 const int *ptI=_nodal_connec_index->getConstPointer();
3000 const int *pt=_nodal_connec->getConstPointer();
3001 int nbOfCells=getNumberOfCells();
3003 for(int i=0;i<nbOfCells;i++)
3004 if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
3010 * Returns the nodal connectivity of a given cell.
3011 * The separator of faces within polyhedron connectivity (-1) is not returned, thus
3012 * all returned node ids can be used in getCoordinatesOfNode().
3013 * \param [in] cellId - an id of the cell of interest.
3014 * \param [in,out] conn - a vector where the node ids are appended. It is not
3015 * cleared before the appending.
3016 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
3018 void MEDCouplingUMesh::getNodeIdsOfCell(int cellId, std::vector<int>& conn) const
3020 const int *ptI=_nodal_connec_index->getConstPointer();
3021 const int *pt=_nodal_connec->getConstPointer();
3022 for(const int *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
3027 std::string MEDCouplingUMesh::simpleRepr() const
3029 static const char msg0[]="No coordinates specified !";
3030 std::ostringstream ret;
3031 ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
3032 ret << "Description of mesh : \"" << getDescription() << "\"\n";
3034 double tt=getTime(tmpp1,tmpp2);
3035 ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
3036 ret << "Iteration : " << tmpp1 << " Order : " << tmpp2 << "\n";
3038 { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
3040 { ret << " Mesh dimension has not been set or is invalid !"; }
3043 const int spaceDim=getSpaceDimension();
3044 ret << spaceDim << "\nInfo attached on space dimension : ";
3045 for(int i=0;i<spaceDim;i++)
3046 ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
3050 ret << msg0 << "\n";
3051 ret << "Number of nodes : ";
3053 ret << getNumberOfNodes() << "\n";
3055 ret << msg0 << "\n";
3056 ret << "Number of cells : ";
3057 if(_nodal_connec!=0 && _nodal_connec_index!=0)
3058 ret << getNumberOfCells() << "\n";
3060 ret << "No connectivity specified !" << "\n";
3061 ret << "Cell types present : ";
3062 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
3064 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
3065 ret << cm.getRepr() << " ";
3071 std::string MEDCouplingUMesh::advancedRepr() const
3073 std::ostringstream ret;
3074 ret << simpleRepr();
3075 ret << "\nCoordinates array : \n___________________\n\n";
3077 _coords->reprWithoutNameStream(ret);
3079 ret << "No array set !\n";
3080 ret << "\n\nConnectivity arrays : \n_____________________\n\n";
3081 reprConnectivityOfThisLL(ret);
3086 * This method returns a C++ code that is a dump of \a this.
3087 * This method will throw if this is not fully defined.
3089 std::string MEDCouplingUMesh::cppRepr() const
3091 static const char coordsName[]="coords";
3092 static const char connName[]="conn";
3093 static const char connIName[]="connI";
3094 checkFullyDefined();
3095 std::ostringstream ret; ret << "// coordinates" << std::endl;
3096 _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
3097 _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
3098 _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
3099 ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
3100 ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
3101 ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
3102 ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
3106 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
3108 std::ostringstream ret;
3109 reprConnectivityOfThisLL(ret);
3114 * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsability to deal with.
3115 * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
3116 * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
3119 * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
3120 * 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
3121 * with number of tuples set to 0, if not the array is taken as this in the returned instance.
3123 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(int spaceDim) const
3125 int mdim=getMeshDimension();
3127 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
3128 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
3129 MCAuto<DataArrayInt> tmp1,tmp2;
3130 bool needToCpyCT=true;
3133 tmp1=DataArrayInt::New(); tmp1->alloc(0,1);
3141 if(!_nodal_connec_index)
3143 tmp2=DataArrayInt::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
3148 tmp2=_nodal_connec_index;
3151 ret->setConnectivity(tmp1,tmp2,false);
3156 MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
3157 ret->setCoords(coords);
3160 ret->setCoords(_coords);
3164 void MEDCouplingUMesh::reprConnectivityOfThisLL(std::ostringstream& stream) const
3166 if(_nodal_connec!=0 && _nodal_connec_index!=0)
3168 int nbOfCells=getNumberOfCells();
3169 const int *c=_nodal_connec->getConstPointer();
3170 const int *ci=_nodal_connec_index->getConstPointer();
3171 for(int i=0;i<nbOfCells;i++)
3173 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[i]]);
3174 stream << "Cell #" << i << " " << cm.getRepr() << " : ";
3175 std::copy(c+ci[i]+1,c+ci[i+1],std::ostream_iterator<int>(stream," "));
3180 stream << "Connectivity not defined !\n";
3183 int MEDCouplingUMesh::getNumberOfNodesInCell(int cellId) const
3185 const int *ptI=_nodal_connec_index->getConstPointer();
3186 const int *pt=_nodal_connec->getConstPointer();
3187 if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
3188 return ptI[cellId+1]-ptI[cellId]-1;
3190 return (int)std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind2nd(std::not_equal_to<int>(),-1));
3194 * Returns types of cells of the specified part of \a this mesh.
3195 * This method avoids computing sub-mesh explicitely to get its types.
3196 * \param [in] begin - an array of cell ids of interest.
3197 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3198 * \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3199 * describing the cell types.
3200 * \throw If the coordinates array is not set.
3201 * \throw If the nodal connectivity of cells is not defined.
3202 * \sa getAllGeoTypes()
3204 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const int *begin, const int *end) const
3206 checkFullyDefined();
3207 std::set<INTERP_KERNEL::NormalizedCellType> ret;
3208 const int *conn=_nodal_connec->getConstPointer();
3209 const int *connIndex=_nodal_connec_index->getConstPointer();
3210 for(const int *w=begin;w!=end;w++)
3211 ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3216 * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3217 * Optionally updates
3218 * a set of types of cells constituting \a this mesh.
3219 * This method is for advanced users having prepared their connectivity before. For
3220 * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3221 * \param [in] conn - the nodal connectivity array.
3222 * \param [in] connIndex - the nodal connectivity index array.
3223 * \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3226 void MEDCouplingUMesh::setConnectivity(DataArrayInt *conn, DataArrayInt *connIndex, bool isComputingTypes)
3228 DataArrayInt::SetArrayIn(conn,_nodal_connec);
3229 DataArrayInt::SetArrayIn(connIndex,_nodal_connec_index);
3230 if(isComputingTypes)
3236 * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3237 * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3239 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCopy):MEDCouplingPointSet(other,deepCopy),_mesh_dim(other._mesh_dim),
3240 _nodal_connec(0),_nodal_connec_index(0),
3241 _types(other._types)
3243 if(other._nodal_connec)
3244 _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCopy);
3245 if(other._nodal_connec_index)
3246 _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCopy);
3249 MEDCouplingUMesh::~MEDCouplingUMesh()
3252 _nodal_connec->decrRef();
3253 if(_nodal_connec_index)
3254 _nodal_connec_index->decrRef();
3258 * Recomputes a set of cell types of \a this mesh. For more info see
3259 * \ref MEDCouplingUMeshNodalConnectivity.
3261 void MEDCouplingUMesh::computeTypes()
3263 ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3267 * This method checks that all arrays are set. If yes nothing done if no an exception is thrown.
3269 void MEDCouplingUMesh::checkFullyDefined() const
3271 if(!_nodal_connec_index || !_nodal_connec || !_coords)
3272 throw INTERP_KERNEL::Exception("Reverse nodal connectivity computation requires full connectivity and coordinates set in unstructured mesh.");
3276 * This method checks that all connectivity arrays are set. If yes nothing done if no an exception is thrown.
3278 void MEDCouplingUMesh::checkConnectivityFullyDefined() const
3280 if(!_nodal_connec_index || !_nodal_connec)
3281 throw INTERP_KERNEL::Exception("Reverse nodal connectivity computation requires full connectivity set in unstructured mesh.");
3285 * Returns a number of cells constituting \a this mesh.
3286 * \return int - the number of cells in \a this mesh.
3287 * \throw If the nodal connectivity of cells is not defined.
3289 int MEDCouplingUMesh::getNumberOfCells() const
3291 if(_nodal_connec_index)
3292 return _nodal_connec_index->getNumberOfTuples()-1;
3297 throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3301 * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3302 * mesh. For more info see \ref meshes.
3303 * \return int - the dimension of \a this mesh.
3304 * \throw If the mesh dimension is not defined using setMeshDimension().
3306 int MEDCouplingUMesh::getMeshDimension() const
3309 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3314 * Returns a length of the nodal connectivity array.
3315 * This method is for test reason. Normally the integer returned is not useable by
3316 * user. For more info see \ref MEDCouplingUMeshNodalConnectivity.
3317 * \return int - the length of the nodal connectivity array.
3319 int MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3321 return _nodal_connec->getNbOfElems();
3325 * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3327 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<int>& tinyInfo, std::vector<std::string>& littleStrings) const
3329 MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3330 tinyInfo.push_back(getMeshDimension());
3331 tinyInfo.push_back(getNumberOfCells());
3333 tinyInfo.push_back(getNodalConnectivityArrayLen());
3335 tinyInfo.push_back(-1);
3339 * First step of unserialization process.
3341 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<int>& tinyInfo) const
3343 return tinyInfo[6]<=0;
3347 * Second step of serialization process.
3348 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3351 * \param littleStrings
3353 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<int>& tinyInfo, DataArrayInt *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3355 MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3357 a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3361 * Third and final step of serialization process.
3363 void MEDCouplingUMesh::serialize(DataArrayInt *&a1, DataArrayDouble *&a2) const
3365 MEDCouplingPointSet::serialize(a1,a2);
3366 if(getMeshDimension()>-1)
3368 a1=DataArrayInt::New();
3369 a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3370 int *ptA1=a1->getPointer();
3371 const int *conn=getNodalConnectivity()->getConstPointer();
3372 const int *index=getNodalConnectivityIndex()->getConstPointer();
3373 ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3374 std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3381 * Second and final unserialization process.
3382 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3384 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<int>& tinyInfo, const DataArrayInt *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3386 MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3387 setMeshDimension(tinyInfo[5]);
3391 const int *recvBuffer=a1->getConstPointer();
3392 MCAuto<DataArrayInt> myConnecIndex=DataArrayInt::New();
3393 myConnecIndex->alloc(tinyInfo[6]+1,1);
3394 std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3395 MCAuto<DataArrayInt> myConnec=DataArrayInt::New();
3396 myConnec->alloc(tinyInfo[7],1);
3397 std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3398 setConnectivity(myConnec, myConnecIndex);
3403 * This is the low algorithm of MEDCouplingUMesh::buildPartOfMySelfSlice.
3404 * CellIds are given using range specified by a start an end and step.
3406 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice(int start, int end, int step) const
3408 checkFullyDefined();
3409 int ncell=getNumberOfCells();
3410 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New();
3411 ret->_mesh_dim=_mesh_dim;
3412 ret->setCoords(_coords);
3413 int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice : ");
3414 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(newNbOfCells+1,1);
3415 int *newConnIPtr=newConnI->getPointer(); *newConnIPtr=0;
3417 const int *conn=_nodal_connec->getConstPointer();
3418 const int *connIndex=_nodal_connec_index->getConstPointer();
3419 for(int i=0;i<newNbOfCells;i++,newConnIPtr++,work+=step)
3421 if(work>=0 && work<ncell)
3423 newConnIPtr[1]=newConnIPtr[0]+connIndex[work+1]-connIndex[work];
3427 std::ostringstream oss; oss << "MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice : On pos #" << i << " input cell id =" << work << " should be in [0," << ncell << ") !";
3428 throw INTERP_KERNEL::Exception(oss.str());
3431 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(newConnIPtr[0],1);
3432 int *newConnPtr=newConn->getPointer();
3433 std::set<INTERP_KERNEL::NormalizedCellType> types;
3435 for(int i=0;i<newNbOfCells;i++,newConnIPtr++,work+=step)
3437 types.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[work]]);
3438 newConnPtr=std::copy(conn+connIndex[work],conn+connIndex[work+1],newConnPtr);
3440 ret->setConnectivity(newConn,newConnI,false);
3442 ret->copyTinyInfoFrom(this);
3447 * This is the low algorithm of MEDCouplingUMesh::buildPartOfMySelf.
3448 * Keeps from \a this only cells which constituing point id are in the ids specified by [ \a begin,\a end ).
3449 * The return newly allocated mesh will share the same coordinates as \a this.
3451 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfKeepCoords(const int *begin, const int *end) const
3453 checkConnectivityFullyDefined();
3454 int ncell=getNumberOfCells();
3455 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New();
3456 ret->_mesh_dim=_mesh_dim;
3457 ret->setCoords(_coords);
3458 std::size_t nbOfElemsRet=std::distance(begin,end);
3459 int *connIndexRet=(int *)malloc((nbOfElemsRet+1)*sizeof(int));
3461 const int *conn=_nodal_connec->getConstPointer();
3462 const int *connIndex=_nodal_connec_index->getConstPointer();
3464 for(const int *work=begin;work!=end;work++,newNbring++)
3466 if(*work>=0 && *work<ncell)
3467 connIndexRet[newNbring+1]=connIndexRet[newNbring]+connIndex[*work+1]-connIndex[*work];
3471 std::ostringstream oss; oss << "MEDCouplingUMesh::buildPartOfMySelfKeepCoords : On pos #" << std::distance(begin,work) << " input cell id =" << *work << " should be in [0," << ncell << ") !";
3472 throw INTERP_KERNEL::Exception(oss.str());
3475 int *connRet=(int *)malloc(connIndexRet[nbOfElemsRet]*sizeof(int));
3476 int *connRetWork=connRet;
3477 std::set<INTERP_KERNEL::NormalizedCellType> types;
3478 for(const int *work=begin;work!=end;work++)
3480 types.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*work]]);
3481 connRetWork=std::copy(conn+connIndex[*work],conn+connIndex[*work+1],connRetWork);
3483 MCAuto<DataArrayInt> connRetArr=DataArrayInt::New();
3484 connRetArr->useArray(connRet,true,C_DEALLOC,connIndexRet[nbOfElemsRet],1);
3485 MCAuto<DataArrayInt> connIndexRetArr=DataArrayInt::New();
3486 connIndexRetArr->useArray(connIndexRet,true,C_DEALLOC,(int)nbOfElemsRet+1,1);
3487 ret->setConnectivity(connRetArr,connIndexRetArr,false);
3489 ret->copyTinyInfoFrom(this);
3494 * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3496 * For 1D cells, the returned field contains lengths.<br>
3497 * For 2D cells, the returned field contains areas.<br>
3498 * For 3D cells, the returned field contains volumes.
3499 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3500 * orientation, i.e. the volume is always positive.
3501 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3502 * and one time . The caller is to delete this field using decrRef() as it is no
3505 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3507 std::string name="MeasureOfMesh_";
3509 int nbelem=getNumberOfCells();
3510 MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3511 field->setName(name);
3512 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3513 array->alloc(nbelem,1);
3514 double *area_vol=array->getPointer();
3515 field->setArray(array) ; array=0;
3516 field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3517 field->synchronizeTimeWithMesh();
3518 if(getMeshDimension()!=-1)
3521 INTERP_KERNEL::NormalizedCellType type;
3522 int dim_space=getSpaceDimension();
3523 const double *coords=getCoords()->getConstPointer();
3524 const int *connec=getNodalConnectivity()->getConstPointer();
3525 const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3526 for(int iel=0;iel<nbelem;iel++)
3528 ipt=connec_index[iel];
3529 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3530 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);
3533 std::transform(area_vol,area_vol+nbelem,area_vol,std::ptr_fun<double,double>(fabs));
3537 area_vol[0]=std::numeric_limits<double>::max();
3539 return field.retn();
3543 * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3545 * For 1D cells, the returned array contains lengths.<br>
3546 * For 2D cells, the returned array contains areas.<br>
3547 * For 3D cells, the returned array contains volumes.
3548 * This method avoids building explicitly a part of \a this mesh to perform the work.
3549 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3550 * orientation, i.e. the volume is always positive.
3551 * \param [in] begin - an array of cell ids of interest.
3552 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3553 * \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3554 * delete this array using decrRef() as it is no more needed.
3556 * \if ENABLE_EXAMPLES
3557 * \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3558 * \ref py_mcumesh_getPartMeasureField "Here is a Python example".
3560 * \sa getMeasureField()
3562 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const int *begin, const int *end) const
3564 std::string name="PartMeasureOfMesh_";
3566 int nbelem=(int)std::distance(begin,end);
3567 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3568 array->setName(name);
3569 array->alloc(nbelem,1);
3570 double *area_vol=array->getPointer();
3571 if(getMeshDimension()!=-1)
3574 INTERP_KERNEL::NormalizedCellType type;
3575 int dim_space=getSpaceDimension();
3576 const double *coords=getCoords()->getConstPointer();
3577 const int *connec=getNodalConnectivity()->getConstPointer();
3578 const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3579 for(const int *iel=begin;iel!=end;iel++)
3581 ipt=connec_index[*iel];
3582 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3583 *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<int,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3586 std::transform(array->getPointer(),area_vol,array->getPointer(),std::ptr_fun<double,double>(fabs));
3590 area_vol[0]=std::numeric_limits<double>::max();
3592 return array.retn();
3596 * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3597 * \a this one. The returned field contains the dual cell volume for each corresponding
3598 * node in \a this mesh. In other words, the field returns the getMeasureField() of
3599 * the dual mesh in P1 sens of \a this.<br>
3600 * For 1D cells, the returned field contains lengths.<br>
3601 * For 2D cells, the returned field contains areas.<br>
3602 * For 3D cells, the returned field contains volumes.
3603 * This method is useful to check "P1*" conservative interpolators.
3604 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3605 * orientation, i.e. the volume is always positive.
3606 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3607 * nodes and one time. The caller is to delete this array using decrRef() as
3608 * it is no more needed.
3610 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3612 MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3613 std::string name="MeasureOnNodeOfMesh_";
3615 int nbNodes=getNumberOfNodes();
3616 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3617 double cst=1./((double)getMeshDimension()+1.);
3618 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3619 array->alloc(nbNodes,1);
3620 double *valsToFill=array->getPointer();
3621 std::fill(valsToFill,valsToFill+nbNodes,0.);
3622 const double *values=tmp->getArray()->getConstPointer();
3623 MCAuto<DataArrayInt> da=DataArrayInt::New();
3624 MCAuto<DataArrayInt> daInd=DataArrayInt::New();
3625 getReverseNodalConnectivity(da,daInd);
3626 const int *daPtr=da->getConstPointer();
3627 const int *daIPtr=daInd->getConstPointer();
3628 for(int i=0;i<nbNodes;i++)
3629 for(const int *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3630 valsToFill[i]+=cst*values[*cell];
3632 ret->setArray(array);
3637 * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3638 * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3639 * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3640 * and are normalized.
3641 * <br> \a this can be either
3642 * - a 2D mesh in 2D or 3D space or
3643 * - an 1D mesh in 2D space.
3645 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3646 * cells and one time. The caller is to delete this field using decrRef() as
3647 * it is no more needed.
3648 * \throw If the nodal connectivity of cells is not defined.
3649 * \throw If the coordinates array is not set.
3650 * \throw If the mesh dimension is not set.
3651 * \throw If the mesh and space dimension is not as specified above.
3653 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3655 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3656 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3657 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3658 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3659 int nbOfCells=getNumberOfCells();
3660 int nbComp=getMeshDimension()+1;
3661 array->alloc(nbOfCells,nbComp);
3662 double *vals=array->getPointer();
3663 const int *connI=_nodal_connec_index->getConstPointer();
3664 const int *conn=_nodal_connec->getConstPointer();
3665 const double *coords=_coords->getConstPointer();
3666 if(getMeshDimension()==2)
3668 if(getSpaceDimension()==3)
3670 MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3671 const double *locPtr=loc->getConstPointer();
3672 for(int i=0;i<nbOfCells;i++,vals+=3)
3674 int offset=connI[i];
3675 INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3676 double n=INTERP_KERNEL::norm<3>(vals);
3677 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3682 MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3683 const double *isAbsPtr=isAbs->getArray()->begin();
3684 for(int i=0;i<nbOfCells;i++,isAbsPtr++)
3685 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3688 else//meshdimension==1
3691 for(int i=0;i<nbOfCells;i++)
3693 int offset=connI[i];
3694 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3695 double n=INTERP_KERNEL::norm<2>(tmp);
3696 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3701 ret->setArray(array);
3703 ret->synchronizeTimeWithSupport();
3708 * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3709 * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3710 * and are normalized.
3711 * <br> \a this can be either
3712 * - a 2D mesh in 2D or 3D space or
3713 * - an 1D mesh in 2D space.
3715 * This method avoids building explicitly a part of \a this mesh to perform the work.
3716 * \param [in] begin - an array of cell ids of interest.
3717 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3718 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3719 * cells and one time. The caller is to delete this field using decrRef() as
3720 * it is no more needed.
3721 * \throw If the nodal connectivity of cells is not defined.
3722 * \throw If the coordinates array is not set.
3723 * \throw If the mesh dimension is not set.
3724 * \throw If the mesh and space dimension is not as specified above.
3725 * \sa buildOrthogonalField()
3727 * \if ENABLE_EXAMPLES
3728 * \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3729 * \ref py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3732 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const int *begin, const int *end) const
3734 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3735 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3736 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3737 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3738 std::size_t nbelems=std::distance(begin,end);
3739 int nbComp=getMeshDimension()+1;
3740 array->alloc((int)nbelems,nbComp);
3741 double *vals=array->getPointer();
3742 const int *connI=_nodal_connec_index->getConstPointer();
3743 const int *conn=_nodal_connec->getConstPointer();
3744 const double *coords=_coords->getConstPointer();
3745 if(getMeshDimension()==2)
3747 if(getSpaceDimension()==3)
3749 MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3750 const double *locPtr=loc->getConstPointer();
3751 for(const int *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3753 int offset=connI[*i];
3754 INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3755 double n=INTERP_KERNEL::norm<3>(vals);
3756 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3761 for(std::size_t i=0;i<nbelems;i++)
3762 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3765 else//meshdimension==1
3768 for(const int *i=begin;i!=end;i++)
3770 int offset=connI[*i];
3771 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3772 double n=INTERP_KERNEL::norm<2>(tmp);
3773 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3778 ret->setArray(array);
3780 ret->synchronizeTimeWithSupport();
3785 * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3786 * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3787 * and are \b not normalized.
3788 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3789 * cells and one time. The caller is to delete this field using decrRef() as
3790 * it is no more needed.
3791 * \throw If the nodal connectivity of cells is not defined.
3792 * \throw If the coordinates array is not set.
3793 * \throw If \a this->getMeshDimension() != 1.
3794 * \throw If \a this mesh includes cells of type other than SEG2.
3796 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3798 if(getMeshDimension()!=1)
3799 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3800 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3801 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3802 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3803 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3804 int nbOfCells=getNumberOfCells();
3805 int spaceDim=getSpaceDimension();
3806 array->alloc(nbOfCells,spaceDim);
3807 double *pt=array->getPointer();
3808 const double *coo=getCoords()->getConstPointer();
3809 std::vector<int> conn;
3811 for(int i=0;i<nbOfCells;i++)
3814 getNodeIdsOfCell(i,conn);
3815 pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3817 ret->setArray(array);
3819 ret->synchronizeTimeWithSupport();
3824 * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3825 * returns a new DataArrayInt, of length equal to the number of 2D cells in the result
3826 * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3827 * from. If a result face is shared by two 3D cells, then the face in included twice in
3829 * \param [in] origin - 3 components of a point defining location of the plane.
3830 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3831 * must be greater than 1e-6.
3832 * \param [in] eps - half-thickness of the plane.
3833 * \param [out] cellIds - a new instance of DataArrayInt holding ids of 3D cells
3834 * producing correspondent 2D cells. The caller is to delete this array
3835 * using decrRef() as it is no more needed.
3836 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3837 * not share the node coordinates array with \a this mesh. The caller is to
3838 * delete this mesh using decrRef() as it is no more needed.
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() != 3 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 3D cell of \a this mesh.
3844 * \throw If \a this includes quadratic cells.
3846 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3848 checkFullyDefined();
3849 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3850 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3851 MCAuto<DataArrayInt> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3852 if(candidates->empty())
3853 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D 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(),desc2=DataArrayInt::New();
3859 MCAuto<DataArrayInt> descIndx1=DataArrayInt::New(),descIndx2=DataArrayInt::New();
3860 MCAuto<DataArrayInt> revDesc1=DataArrayInt::New(),revDesc2=DataArrayInt::New();
3861 MCAuto<DataArrayInt> revDescIndx1=DataArrayInt::New(),revDescIndx2=DataArrayInt::New();
3862 MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3863 revDesc2=0; revDescIndx2=0;
3864 MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3865 revDesc1=0; revDescIndx1=0;
3866 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3867 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3869 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3870 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3872 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3873 std::vector< std::pair<int,int> > cut3DSurf(mDesc2->getNumberOfCells());
3874 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3875 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3876 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3877 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New());
3878 connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3879 subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3880 if(cellIds2->empty())
3881 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3882 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3883 ret->setCoords(mDesc1->getCoords());
3884 ret->setConnectivity(conn,connI,true);
3885 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3890 * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3891 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
3892 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3894 * \param [in] origin - 3 components of a point defining location of the plane.
3895 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3896 * must be greater than 1e-6.
3897 * \param [in] eps - half-thickness of the plane.
3898 * \param [out] cellIds - a new instance of DataArrayInt holding ids of faces
3899 * producing correspondent segments. The caller is to delete this array
3900 * using decrRef() as it is no more needed.
3901 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3902 * mesh in 3D space. This mesh does not share the node coordinates array with
3903 * \a this mesh. The caller is to delete this mesh using decrRef() as it is
3905 * \throw If the coordinates array is not set.
3906 * \throw If the nodal connectivity of cells is not defined.
3907 * \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3908 * \throw If magnitude of \a vec is less than 1e-6.
3909 * \throw If the plane does not intersect any 2D cell of \a this mesh.
3910 * \throw If \a this includes quadratic cells.
3912 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3914 checkFullyDefined();
3915 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3916 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3917 MCAuto<DataArrayInt> candidates(getCellIdsCrossingPlane(origin,vec,eps));
3918 if(candidates->empty())
3919 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3920 std::vector<int> nodes;
3921 DataArrayInt *cellIds1D(0);
3922 MCAuto<MEDCouplingUMesh> subMesh(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3923 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3924 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
3925 MCAuto<MEDCouplingUMesh> mDesc1(subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3926 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3927 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3929 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3930 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3932 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3933 int ncellsSub=subMesh->getNumberOfCells();
3934 std::vector< std::pair<int,int> > cut3DSurf(ncellsSub);
3935 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3936 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3937 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3938 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New()); connI->pushBackSilent(0);
3940 const int *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3941 const int *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3942 for(int i=0;i<ncellsSub;i++)
3944 if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3946 if(cut3DSurf[i].first!=-2)
3948 conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3949 connI->pushBackSilent(conn->getNumberOfTuples());
3950 cellIds2->pushBackSilent(i);
3954 int cellId3DSurf=cut3DSurf[i].second;
3955 int offset=nodalI[cellId3DSurf]+1;
3956 int nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3957 for(int j=0;j<nbOfEdges;j++)
3959 conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3960 connI->pushBackSilent(conn->getNumberOfTuples());
3961 cellIds2->pushBackSilent(cellId3DSurf);
3966 if(cellIds2->empty())
3967 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3968 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3969 ret->setCoords(mDesc1->getCoords());
3970 ret->setConnectivity(conn,connI,true);
3971 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3975 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::clipSingle3DCellByPlane(const double origin[3], const double vec[3], double eps) const
3977 checkFullyDefined();
3978 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3979 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3980 if(getNumberOfCells()!=1)
3981 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works only on mesh containing exactly one cell !");
3983 std::vector<int> nodes;
3984 findNodesOnPlane(origin,vec,eps,nodes);
3985 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),desc2(DataArrayInt::New()),descIndx1(DataArrayInt::New()),descIndx2(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDesc2(DataArrayInt::New()),revDescIndx1(DataArrayInt::New()),revDescIndx2(DataArrayInt::New());
3986 MCAuto<MEDCouplingUMesh> mDesc2(buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2));//meshDim==2 spaceDim==3
3987 revDesc2=0; revDescIndx2=0;
3988 MCAuto<MEDCouplingUMesh> mDesc1(mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3989 revDesc1=0; revDescIndx1=0;
3990 DataArrayInt *cellIds1D(0);
3991 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3992 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3993 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3994 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3996 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3997 std::vector< std::pair<int,int> > cut3DSurf(mDesc2->getNumberOfCells());
3998 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->begin(),mDesc2->getNodalConnectivityIndex()->begin(),
3999 mDesc1->getNodalConnectivity()->begin(),mDesc1->getNodalConnectivityIndex()->begin(),
4000 desc1->begin(),descIndx1->begin(),cut3DSurf);
4001 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New());
4002 connI->pushBackSilent(0); conn->alloc(0,1);
4004 MCAuto<DataArrayInt> cellIds2(DataArrayInt::New()); cellIds2->alloc(0,1);
4005 assemblyForSplitFrom3DSurf(cut3DSurf,desc2->begin(),descIndx2->begin(),conn,connI,cellIds2);
4006 if(cellIds2->empty())
4007 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
4009 std::vector<std::vector<int> > res;
4010 buildSubCellsFromCut(cut3DSurf,desc2->begin(),descIndx2->begin(),mDesc1->getCoords()->begin(),eps,res);
4011 std::size_t sz(res.size());
4012 if(res.size()==mDesc1->getNumberOfCells())
4013 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane : cell is not clipped !");
4014 for(std::size_t i=0;i<sz;i++)
4016 conn->pushBackSilent((int)INTERP_KERNEL::NORM_POLYGON);
4017 conn->insertAtTheEnd(res[i].begin(),res[i].end());
4018 connI->pushBackSilent(conn->getNumberOfTuples());
4020 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
4021 ret->setCoords(mDesc1->getCoords());
4022 ret->setConnectivity(conn,connI,true);
4023 int nbCellsRet(ret->getNumberOfCells());
4025 MCAuto<DataArrayDouble> vec2(DataArrayDouble::New()); vec2->alloc(1,3); std::copy(vec,vec+3,vec2->getPointer());
4026 MCAuto<MEDCouplingFieldDouble> ortho(ret->buildOrthogonalField());
4027 MCAuto<DataArrayDouble> ortho2(ortho->getArray()->selectByTupleIdSafeSlice(0,1,1));
4028 MCAuto<DataArrayDouble> dott(DataArrayDouble::Dot(ortho2,vec2));
4029 MCAuto<DataArrayDouble> ccm(ret->computeCellCenterOfMass());
4030 MCAuto<DataArrayDouble> occm;
4032 MCAuto<DataArrayDouble> pt(DataArrayDouble::New()); pt->alloc(1,3); std::copy(origin,origin+3,pt->getPointer());
4033 occm=DataArrayDouble::Substract(ccm,pt);
4035 vec2=DataArrayDouble::New(); vec2->alloc(nbCellsRet,3);
4036 vec2->setPartOfValuesSimple1(vec[0],0,nbCellsRet,1,0,1,1); vec2->setPartOfValuesSimple1(vec[1],0,nbCellsRet,1,1,2,1); vec2->setPartOfValuesSimple1(vec[2],0,nbCellsRet,1,2,3,1);
4037 MCAuto<DataArrayDouble> dott2(DataArrayDouble::Dot(occm,vec2));
4039 const int *cPtr(ret->getNodalConnectivity()->begin()),*ciPtr(ret->getNodalConnectivityIndex()->begin());
4040 MCAuto<MEDCouplingUMesh> ret2(MEDCouplingUMesh::New("Clip3D",3));
4041 ret2->setCoords(mDesc1->getCoords());
4042 MCAuto<DataArrayInt> conn2(DataArrayInt::New()),conn2I(DataArrayInt::New());
4043 conn2I->pushBackSilent(0); conn2->alloc(0,1);
4044 std::vector<int> cell0(1,(int)INTERP_KERNEL::NORM_POLYHED);
4045 std::vector<int> cell1(1,(int)INTERP_KERNEL::NORM_POLYHED);
4046 if(dott->getIJ(0,0)>0)
4048 cell0.insert(cell0.end(),cPtr+1,cPtr+ciPtr[1]);
4049 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell1,cell1.end()));
4053 cell1.insert(cell1.end(),cPtr+1,cPtr+ciPtr[1]);
4054 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell0,cell0.end()));
4056 for(int i=1;i<nbCellsRet;i++)
4058 if(dott2->getIJ(i,0)<0)
4060 if(ciPtr[i+1]-ciPtr[i]>=4)
4062 cell0.push_back(-1);
4063 cell0.insert(cell0.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
4068 if(ciPtr[i+1]-ciPtr[i]>=4)
4070 cell1.push_back(-1);
4071 cell1.insert(cell1.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
4075 conn2->insertAtTheEnd(cell0.begin(),cell0.end());
4076 conn2I->pushBackSilent(conn2->getNumberOfTuples());
4077 conn2->insertAtTheEnd(cell1.begin(),cell1.end());
4078 conn2I->pushBackSilent(conn2->getNumberOfTuples());
4079 ret2->setConnectivity(conn2,conn2I,true);
4080 ret2->checkConsistencyLight();
4081 ret2->writeVTK("ret2.vtu");
4082 ret2->orientCorrectlyPolyhedrons();
4087 * Finds cells whose bounding boxes intersect a given plane.
4088 * \param [in] origin - 3 components of a point defining location of the plane.
4089 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
4090 * must be greater than 1e-6.
4091 * \param [in] eps - half-thickness of the plane.
4092 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of the found
4093 * cells. The caller is to delete this array using decrRef() as it is no more
4095 * \throw If the coordinates array is not set.
4096 * \throw If the nodal connectivity of cells is not defined.
4097 * \throw If \a this->getSpaceDimension() != 3.
4098 * \throw If magnitude of \a vec is less than 1e-6.
4099 * \sa buildSlice3D()
4101 DataArrayInt *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
4103 checkFullyDefined();
4104 if(getSpaceDimension()!=3)
4105 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
4106 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
4108 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
4110 vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
4111 double angle=acos(vec[2]/normm);
4112 MCAuto<DataArrayInt> cellIds;
4116 MCAuto<DataArrayDouble> coo=_coords->deepCopy();
4117 double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
4118 if(normm2/normm>1e-6)
4119 DataArrayDouble::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer(),coo->getPointer());
4120 MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
4122 mw->getBoundingBox(bbox);
4123 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
4124 cellIds=mw->getCellsInBoundingBox(bbox,eps);
4128 getBoundingBox(bbox);
4129 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
4130 cellIds=getCellsInBoundingBox(bbox,eps);
4132 return cellIds.retn();
4136 * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
4137 * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
4138 * No consideration of coordinate is done by this method.
4139 * 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)
4140 * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be usefull.
4142 bool MEDCouplingUMesh::isContiguous1D() const
4144 if(getMeshDimension()!=1)
4145 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
4146 int nbCells=getNumberOfCells();
4148 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
4149 const int *connI(_nodal_connec_index->begin()),*conn(_nodal_connec->begin());
4150 int ref=conn[connI[0]+2];
4151 for(int i=1;i<nbCells;i++)
4153 if(conn[connI[i]+1]!=ref)
4155 ref=conn[connI[i]+2];
4161 * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
4162 * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
4163 * \param pt reference point of the line
4164 * \param v normalized director vector of the line
4165 * \param eps max precision before throwing an exception
4166 * \param res output of size this->getNumberOfCells
4168 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
4170 if(getMeshDimension()!=1)
4171 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
4172 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
4173 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
4174 if(getSpaceDimension()!=3)
4175 throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
4176 MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
4177 const double *fPtr=f->getArray()->getConstPointer();
4179 for(int i=0;i<getNumberOfCells();i++)
4181 const double *tmp1=fPtr+3*i;
4182 tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
4183 tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
4184 tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
4185 double n1=INTERP_KERNEL::norm<3>(tmp);
4186 n1/=INTERP_KERNEL::norm<3>(tmp1);
4188 throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
4190 const double *coo=getCoords()->getConstPointer();
4191 for(int i=0;i<getNumberOfNodes();i++)
4193 std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
4194 std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
4195 res[i]=std::accumulate(tmp,tmp+3,0.);
4200 * 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.
4201 * \a this is expected to be a mesh so that its space dimension is equal to its
4202 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4203 * 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).
4205 * 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
4206 * 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).
4207 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4209 * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
4210 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4212 * \param [in] ptBg the start pointer (included) of the coordinates of the point
4213 * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
4214 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4215 * \return the positive value of the distance.
4216 * \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
4218 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
4220 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, int& cellId) const
4222 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4223 if(meshDim!=spaceDim-1)
4224 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
4225 if(meshDim!=2 && meshDim!=1)
4226 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
4227 checkFullyDefined();
4228 if((int)std::distance(ptBg,ptEnd)!=spaceDim)
4229 { 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()); }
4230 DataArrayInt *ret1=0;
4231 MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,C_DEALLOC,1,spaceDim);
4232 MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
4233 MCAuto<DataArrayInt> ret1Safe(ret1);
4234 cellId=*ret1Safe->begin();
4235 return *ret0->begin();
4239 * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
4240 * to \a this and the first \a cellId in \a this corresponding to the returned distance.
4241 * 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
4242 * 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).
4243 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4245 * \a this is expected to be a mesh so that its space dimension is equal to its
4246 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4247 * 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).
4249 * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
4250 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4252 * \param [in] pts the list of points in which each tuple represents a point
4253 * \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.
4254 * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
4255 * \throw if number of components of \a pts is not equal to the space dimension.
4256 * \throw if mesh dimension of \a this is not equal to space dimension - 1.
4257 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
4259 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayInt *& cellIds) const
4262 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
4263 pts->checkAllocated();
4264 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4265 if(meshDim!=spaceDim-1)
4266 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
4267 if(meshDim!=2 && meshDim!=1)
4268 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
4269 if(pts->getNumberOfComponents()!=spaceDim)
4271 std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
4272 throw INTERP_KERNEL::Exception(oss.str());
4274 checkFullyDefined();
4275 int nbCells=getNumberOfCells();
4277 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
4278 int nbOfPts=pts->getNumberOfTuples();
4279 MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
4280 MCAuto<DataArrayInt> ret1=DataArrayInt::New(); ret1->alloc(nbOfPts,1);
4281 const int *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
4282 double *ret0Ptr=ret0->getPointer(); int *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
4283 MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
4284 const double *bbox(bboxArr->begin());
4289 BBTreeDst<3> myTree(bbox,0,0,nbCells);
4290 for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
4292 double x=std::numeric_limits<double>::max();
4293 std::vector<int> elems;
4294 myTree.getMinDistanceOfMax(ptsPtr,x);
4295 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4296 DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4302 BBTreeDst<2> myTree(bbox,0,0,nbCells);
4303 for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4305 double x=std::numeric_limits<double>::max();
4306 std::vector<int> elems;
4307 myTree.getMinDistanceOfMax(ptsPtr,x);
4308 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4309 DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4314 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4316 cellIds=ret1.retn();
4323 * \param [in] pt the start pointer (included) of the coordinates of the point
4324 * \param [in] cellIdsBg the start pointer (included) of cellIds
4325 * \param [in] cellIdsEnd the end pointer (excluded) of cellIds
4326 * \param [in] nc nodal connectivity
4327 * \param [in] ncI nodal connectivity index
4328 * \param [in,out] ret0 the min distance between \a this and the external input point
4329 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4330 * \sa MEDCouplingUMesh::distanceToPoint, MEDCouplingUMesh::distanceToPoints
4332 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)
4335 ret0=std::numeric_limits<double>::max();
4336 for(const int *zeCell=cellIdsBg;zeCell!=cellIdsEnd;zeCell++)
4338 switch((INTERP_KERNEL::NormalizedCellType)nc[ncI[*zeCell]])
4340 case INTERP_KERNEL::NORM_TRI3:
4342 double tmp=INTERP_KERNEL::DistanceFromPtToTriInSpaceDim3(pt,coords+3*nc[ncI[*zeCell]+1],coords+3*nc[ncI[*zeCell]+2],coords+3*nc[ncI[*zeCell]+3]);
4344 { ret0=tmp; cellId=*zeCell; }
4347 case INTERP_KERNEL::NORM_QUAD4:
4348 case INTERP_KERNEL::NORM_POLYGON:
4350 double tmp=INTERP_KERNEL::DistanceFromPtToPolygonInSpaceDim3(pt,nc+ncI[*zeCell]+1,nc+ncI[*zeCell+1],coords);
4352 { ret0=tmp; cellId=*zeCell; }
4356 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint3DSurfAlg : not managed cell type ! Supporting TRI3, QUAD4 and POLYGON !");
4362 * \param [in] pt the start pointer (included) of the coordinates of the point
4363 * \param [in] cellIdsBg the start pointer (included) of cellIds
4364 * \param [in] cellIdsEnd the end pointer (excluded) of cellIds
4365 * \param [in] nc nodal connectivity
4366 * \param [in] ncI nodal connectivity index
4367 * \param [in,out] ret0 the min distance between \a this and the external input point
4368 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4369 * \sa MEDCouplingUMesh::distanceToPoint, MEDCouplingUMesh::distanceToPoints
4371 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)
4374 ret0=std::numeric_limits<double>::max();
4375 for(const int *zeCell=cellIdsBg;zeCell!=cellIdsEnd;zeCell++)
4377 switch((INTERP_KERNEL::NormalizedCellType)nc[ncI[*zeCell]])
4379 case INTERP_KERNEL::NORM_SEG2:
4381 std::size_t uselessEntry=0;
4382 double tmp=INTERP_KERNEL::SquareDistanceFromPtToSegInSpaceDim2(pt,coords+2*nc[ncI[*zeCell]+1],coords+2*nc[ncI[*zeCell]+2],uselessEntry);
4385 { ret0=tmp; cellId=*zeCell; }
4389 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint2DCurveAlg : not managed cell type ! Supporting SEG2 !");
4396 * Finds cells in contact with a ball (i.e. a point with precision).
4397 * 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.
4398 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4400 * \warning This method is suitable if the caller intends to evaluate only one
4401 * point, for more points getCellsContainingPoints() is recommended as it is
4403 * \param [in] pos - array of coordinates of the ball central point.
4404 * \param [in] eps - ball radius.
4405 * \return int - a smallest id of cells being in contact with the ball, -1 in case
4406 * if there are no such cells.
4407 * \throw If the coordinates array is not set.
4408 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4410 int MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4412 std::vector<int> elts;
4413 getCellsContainingPoint(pos,eps,elts);
4416 return elts.front();
4420 * Finds cells in contact with a ball (i.e. a point with precision).
4421 * 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.
4422 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4423 * \warning This method is suitable if the caller intends to evaluate only one
4424 * point, for more points getCellsContainingPoints() is recommended as it is
4426 * \param [in] pos - array of coordinates of the ball central point.
4427 * \param [in] eps - ball radius.
4428 * \param [out] elts - vector returning ids of the found cells. It is cleared
4429 * before inserting ids.
4430 * \throw If the coordinates array is not set.
4431 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4433 * \if ENABLE_EXAMPLES
4434 * \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4435 * \ref py_mcumesh_getCellsContainingPoint "Here is a Python example".
4438 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<int>& elts) const
4440 MCAuto<DataArrayInt> eltsUg,eltsIndexUg;
4441 getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4442 elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4447 namespace MEDCoupling
4449 template<const int SPACEDIMM>
4453 static const int MY_SPACEDIM=SPACEDIMM;
4454 static const int MY_MESHDIM=8;
4455 typedef int MyConnType;
4456 static const INTERP_KERNEL::NumberingPolicy My_numPol=INTERP_KERNEL::ALL_C_MODE;
4458 // useless, but for windows compilation ...
4459 const double* getCoordinatesPtr() const { return 0; }
4460 const int* getConnectivityPtr() const { return 0; }
4461 const int* getConnectivityIndexPtr() const { return 0; }
4462 INTERP_KERNEL::NormalizedCellType getTypeOfElement(int) const { return (INTERP_KERNEL::NormalizedCellType)0; }
4466 INTERP_KERNEL::Edge *MEDCouplingUMeshBuildQPFromEdge2(INTERP_KERNEL::NormalizedCellType typ, const int *bg, const double *coords2D, std::map< MCAuto<INTERP_KERNEL::Node>,int>& m)
4468 INTERP_KERNEL::Edge *ret(0);
4469 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]));
4470 m[n0]=bg[0]; m[n1]=bg[1];
4473 case INTERP_KERNEL::NORM_SEG2:
4475 ret=new INTERP_KERNEL::EdgeLin(n0,n1);
4478 case INTERP_KERNEL::NORM_SEG3:
4480 INTERP_KERNEL::Node *n2(new INTERP_KERNEL::Node(coords2D[2*bg[2]],coords2D[2*bg[2]+1])); m[n2]=bg[2];
4481 INTERP_KERNEL::EdgeLin *e1(new INTERP_KERNEL::EdgeLin(n0,n2)),*e2(new INTERP_KERNEL::EdgeLin(n2,n1));
4482 INTERP_KERNEL::SegSegIntersector inters(*e1,*e2);
4483 // is the SEG3 degenerated, and thus can be reduced to a SEG2?
4484 bool colinearity(inters.areColinears());
4485 delete e1; delete e2;
4487 { ret=new INTERP_KERNEL::EdgeLin(n0,n1); }
4489 { ret=new INTERP_KERNEL::EdgeArcCircle(n0,n2,n1); }
4493 throw INTERP_KERNEL::Exception("MEDCouplingUMeshBuildQPFromEdge2 : Expecting a mesh with spaceDim==2 and meshDim==1 !");
4498 INTERP_KERNEL::Edge *MEDCouplingUMeshBuildQPFromEdge(INTERP_KERNEL::NormalizedCellType typ, std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >& mapp2, const int *bg)
4500 INTERP_KERNEL::Edge *ret=0;
4503 case INTERP_KERNEL::NORM_SEG2:
4505 ret=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[1]].first);
4508 case INTERP_KERNEL::NORM_SEG3:
4510 INTERP_KERNEL::EdgeLin *e1=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[2]].first);
4511 INTERP_KERNEL::EdgeLin *e2=new INTERP_KERNEL::EdgeLin(mapp2[bg[2]].first,mapp2[bg[1]].first);
4512 INTERP_KERNEL::SegSegIntersector inters(*e1,*e2);
4513 // is the SEG3 degenerated, and thus can be reduced to a SEG2?
4514 bool colinearity=inters.areColinears();
4515 delete e1; delete e2;
4517 ret=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[1]].first);
4519 ret=new INTERP_KERNEL::EdgeArcCircle(mapp2[bg[0]].first,mapp2[bg[2]].first,mapp2[bg[1]].first);
4520 mapp2[bg[2]].second=false;
4524 throw INTERP_KERNEL::Exception("MEDCouplingUMeshBuildQPFromEdge : Expecting a mesh with spaceDim==2 and meshDim==1 !");
4530 * This method creates a sub mesh in Geometric2D DS. The sub mesh is composed by the sub set of cells in 'candidates' taken from
4531 * the global mesh 'mDesc'.
4532 * The input mesh 'mDesc' must be so that mDim==1 and spaceDim==2.
4533 * 'mapp' returns a mapping between local numbering in submesh (represented by a Node*) and the global node numbering in 'mDesc'.
4535 INTERP_KERNEL::QuadraticPolygon *MEDCouplingUMeshBuildQPFromMesh(const MEDCouplingUMesh *mDesc, const std::vector<int>& candidates,
4536 std::map<INTERP_KERNEL::Node *,int>& mapp)
4539 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.
4540 const double *coo=mDesc->getCoords()->getConstPointer();
4541 const int *c=mDesc->getNodalConnectivity()->getConstPointer();
4542 const int *cI=mDesc->getNodalConnectivityIndex()->getConstPointer();
4544 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
4545 s.insert(c+cI[*it]+1,c+cI[(*it)+1]);
4546 for(std::set<int>::const_iterator it2=s.begin();it2!=s.end();it2++)
4548 INTERP_KERNEL::Node *n=new INTERP_KERNEL::Node(coo[2*(*it2)],coo[2*(*it2)+1]);
4549 mapp2[*it2]=std::pair<INTERP_KERNEL::Node *,bool>(n,true);
4551 INTERP_KERNEL::QuadraticPolygon *ret=new INTERP_KERNEL::QuadraticPolygon;
4552 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
4554 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[*it]];
4555 ret->pushBack(MEDCouplingUMeshBuildQPFromEdge(typ,mapp2,c+cI[*it]+1));
4557 for(std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >::const_iterator it2=mapp2.begin();it2!=mapp2.end();it2++)
4559 if((*it2).second.second)
4560 mapp[(*it2).second.first]=(*it2).first;
4561 ((*it2).second.first)->decrRef();
4566 INTERP_KERNEL::Node *MEDCouplingUMeshBuildQPNode(int nodeId, const double *coo1, int offset1, const double *coo2, int offset2, const std::vector<double>& addCoo)
4570 int locId=nodeId-offset2;
4571 return new INTERP_KERNEL::Node(addCoo[2*locId],addCoo[2*locId+1]);
4575 int locId=nodeId-offset1;
4576 return new INTERP_KERNEL::Node(coo2[2*locId],coo2[2*locId+1]);
4578 return new INTERP_KERNEL::Node(coo1[2*nodeId],coo1[2*nodeId+1]);
4582 * Construct a mapping between set of Nodes and the standart MEDCoupling connectivity format (c, cI).
4584 void MEDCouplingUMeshBuildQPFromMesh3(const double *coo1, int offset1, const double *coo2, int offset2, const std::vector<double>& addCoo,
4585 const int *desc1Bg, const int *desc1End, const std::vector<std::vector<int> >& intesctEdges1,
4586 /*output*/std::map<INTERP_KERNEL::Node *,int>& mapp, std::map<int,INTERP_KERNEL::Node *>& mappRev)
4588 for(const int *desc1=desc1Bg;desc1!=desc1End;desc1++)
4590 int eltId1=abs(*desc1)-1;
4591 for(std::vector<int>::const_iterator it1=intesctEdges1[eltId1].begin();it1!=intesctEdges1[eltId1].end();it1++)
4593 std::map<int,INTERP_KERNEL::Node *>::const_iterator it=mappRev.find(*it1);
4594 if(it==mappRev.end())
4596 INTERP_KERNEL::Node *node=MEDCouplingUMeshBuildQPNode(*it1,coo1,offset1,coo2,offset2,addCoo);
4607 template<int SPACEDIM>
4608 void MEDCouplingUMesh::getCellsContainingPointsAlg(const double *coords, const double *pos, int nbOfPoints,
4609 double eps, MCAuto<DataArrayInt>& elts, MCAuto<DataArrayInt>& eltsIndex) const
4611 elts=DataArrayInt::New(); eltsIndex=DataArrayInt::New(); eltsIndex->alloc(nbOfPoints+1,1); eltsIndex->setIJ(0,0,0); elts->alloc(0,1);
4612 int *eltsIndexPtr(eltsIndex->getPointer());
4613 MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree(eps));
4614 const double *bbox(bboxArr->begin());
4615 int nbOfCells=getNumberOfCells();
4616 const int *conn=_nodal_connec->getConstPointer();
4617 const int *connI=_nodal_connec_index->getConstPointer();
4618 double bb[2*SPACEDIM];
4619 BBTree<SPACEDIM,int> myTree(&bbox[0],0,0,nbOfCells,-eps);
4620 for(int i=0;i<nbOfPoints;i++)
4622 eltsIndexPtr[i+1]=eltsIndexPtr[i];
4623 for(int j=0;j<SPACEDIM;j++)
4625 bb[2*j]=pos[SPACEDIM*i+j];
4626 bb[2*j+1]=pos[SPACEDIM*i+j];
4628 std::vector<int> candidates;
4629 myTree.getIntersectingElems(bb,candidates);
4630 for(std::vector<int>::const_iterator iter=candidates.begin();iter!=candidates.end();iter++)
4632 int sz(connI[(*iter)+1]-connI[*iter]-1);
4633 INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[connI[*iter]]);
4635 if(ct!=INTERP_KERNEL::NORM_POLYGON && ct!=INTERP_KERNEL::NORM_QPOLYG)
4636 status=INTERP_KERNEL::PointLocatorAlgos<DummyClsMCUG<SPACEDIM> >::isElementContainsPoint(pos+i*SPACEDIM,ct,coords,conn+connI[*iter]+1,sz,eps);
4640 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPointsAlg : not implemented yet for POLYGON and QPOLYGON in spaceDim 3 !");
4641 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
4642 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
4643 std::vector<INTERP_KERNEL::Node *> nodes(sz);
4644 INTERP_KERNEL::QuadraticPolygon *pol(0);
4645 for(int j=0;j<sz;j++)
4647 int nodeId(conn[connI[*iter]+1+j]);
4648 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*SPACEDIM],coords[nodeId*SPACEDIM+1]);
4650 if(!INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic())
4651 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
4653 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
4654 INTERP_KERNEL::Node *n(new INTERP_KERNEL::Node(pos[i*SPACEDIM],pos[i*SPACEDIM+1]));
4655 double a(0.),b(0.),c(0.);
4656 a=pol->normalizeMe(b,c); n->applySimilarity(b,c,a);
4657 status=pol->isInOrOut2(n);
4658 delete pol; n->decrRef();
4662 eltsIndexPtr[i+1]++;
4663 elts->pushBackSilent(*iter);
4669 * Finds cells in contact with several balls (i.e. points with precision).
4670 * This method is an extension of getCellContainingPoint() and
4671 * getCellsContainingPoint() for the case of multiple points.
4672 * 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.
4673 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4674 * \param [in] pos - an array of coordinates of points in full interlace mode :
4675 * X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4676 * this->getSpaceDimension() * \a nbOfPoints
4677 * \param [in] nbOfPoints - number of points to locate within \a this mesh.
4678 * \param [in] eps - radius of balls (i.e. the precision).
4679 * \param [out] elts - vector returning ids of found cells.
4680 * \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4681 * dividing cell ids in \a elts into groups each referring to one
4682 * point. Its every element (except the last one) is an index pointing to the
4683 * first id of a group of cells. For example cells in contact with the *i*-th
4684 * point are described by following range of indices:
4685 * [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4686 * \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4687 * Number of cells in contact with the *i*-th point is
4688 * \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4689 * \throw If the coordinates array is not set.
4690 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4692 * \if ENABLE_EXAMPLES
4693 * \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4694 * \ref py_mcumesh_getCellsContainingPoints "Here is a Python example".
4697 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, int nbOfPoints, double eps,
4698 MCAuto<DataArrayInt>& elts, MCAuto<DataArrayInt>& eltsIndex) const
4700 int spaceDim=getSpaceDimension();
4701 int mDim=getMeshDimension();
4706 const double *coords=_coords->getConstPointer();
4707 getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4714 throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4716 else if(spaceDim==2)
4720 const double *coords=_coords->getConstPointer();
4721 getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4724 throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4726 else if(spaceDim==1)
4730 const double *coords=_coords->getConstPointer();
4731 getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4734 throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4737 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4741 * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4742 * least two its edges intersect each other anywhere except their extremities. An
4743 * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4744 * \param [in,out] cells - a vector returning ids of the found cells. It is not
4745 * cleared before filling in.
4746 * \param [in] eps - precision.
4747 * \throw If \a this->getMeshDimension() != 2.
4748 * \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4750 void MEDCouplingUMesh::checkButterflyCells(std::vector<int>& cells, double eps) const
4752 const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4753 if(getMeshDimension()!=2)
4754 throw INTERP_KERNEL::Exception(msg);
4755 int spaceDim=getSpaceDimension();
4756 if(spaceDim!=2 && spaceDim!=3)
4757 throw INTERP_KERNEL::Exception(msg);
4758 const int *conn=_nodal_connec->getConstPointer();
4759 const int *connI=_nodal_connec_index->getConstPointer();
4760 int nbOfCells=getNumberOfCells();
4761 std::vector<double> cell2DinS2;
4762 for(int i=0;i<nbOfCells;i++)
4764 int offset=connI[i];
4765 int nbOfNodesForCell=connI[i+1]-offset-1;
4766 if(nbOfNodesForCell<=3)
4768 bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4769 project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4770 if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4777 * This method is typically requested to unbutterfly 2D linear cells in \b this.
4779 * 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.
4780 * 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.
4782 * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4783 * This convex envelop is computed using Jarvis march algorithm.
4784 * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4785 * 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)
4786 * 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.
4788 * \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.
4789 * \sa MEDCouplingUMesh::colinearize2D
4791 DataArrayInt *MEDCouplingUMesh::convexEnvelop2D()
4793 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4794 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D works only for meshDim=2 and spaceDim=2 !");
4795 checkFullyDefined();
4796 const double *coords=getCoords()->getConstPointer();
4797 int nbOfCells=getNumberOfCells();
4798 MCAuto<DataArrayInt> nodalConnecIndexOut=DataArrayInt::New();
4799 nodalConnecIndexOut->alloc(nbOfCells+1,1);
4800 MCAuto<DataArrayInt> nodalConnecOut(DataArrayInt::New());
4801 int *workIndexOut=nodalConnecIndexOut->getPointer();
4803 const int *nodalConnecIn=_nodal_connec->getConstPointer();
4804 const int *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4805 std::set<INTERP_KERNEL::NormalizedCellType> types;
4806 MCAuto<DataArrayInt> isChanged(DataArrayInt::New());
4807 isChanged->alloc(0,1);
4808 for(int i=0;i<nbOfCells;i++,workIndexOut++)
4810 int pos=nodalConnecOut->getNumberOfTuples();
4811 if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4812 isChanged->pushBackSilent(i);
4813 types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4814 workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4816 if(isChanged->empty())
4818 setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4820 return isChanged.retn();
4824 * This method is \b NOT const because it can modify \a this.
4825 * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4826 * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4827 * \param policy specifies the type of extrusion chosen:
4828 * - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4829 * will be repeated to build each level
4830 * - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4831 * 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
4832 * 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
4834 * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4836 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4838 checkFullyDefined();
4839 mesh1D->checkFullyDefined();
4840 if(!mesh1D->isContiguous1D())
4841 throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4842 if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4843 throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4844 if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4845 throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4846 if(mesh1D->getMeshDimension()!=1)
4847 throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4849 if(isPresenceOfQuadratic())
4851 if(mesh1D->isFullyQuadratic())
4854 throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4856 int oldNbOfNodes(getNumberOfNodes());
4857 MCAuto<DataArrayDouble> newCoords;
4862 newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4867 newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4871 throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4873 setCoords(newCoords);
4874 MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4880 * This method works on a 3D curve linear mesh that is to say (meshDim==1 and spaceDim==3).
4881 * If it is not the case an exception will be thrown.
4882 * This method is non const because the coordinate of \a this can be appended with some new points issued from
4883 * intersection of plane defined by ('origin','vec').
4884 * This method has one in/out parameter : 'cut3DCurve'.
4885 * Param 'cut3DCurve' is expected to be of size 'this->getNumberOfCells()'. For each i in [0,'this->getNumberOfCells()')
4886 * if cut3DCurve[i]==-2, it means that for cell #i in \a this nothing has been detected previously.
4887 * if cut3DCurve[i]==-1, it means that cell#i has been already detected to be fully part of plane defined by ('origin','vec').
4888 * This method will throw an exception if \a this contains a non linear segment.
4890 void MEDCouplingUMesh::split3DCurveWithPlane(const double *origin, const double *vec, double eps, std::vector<int>& cut3DCurve)
4892 checkFullyDefined();
4893 if(getMeshDimension()!=1 || getSpaceDimension()!=3)
4894 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane works on umeshes with meshdim equal to 1 and spaceDim equal to 3 !");
4895 int ncells=getNumberOfCells();
4896 int nnodes=getNumberOfNodes();
4897 double vec2[3],vec3[3],vec4[3];
4898 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
4900 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
4901 vec2[0]=vec[0]/normm; vec2[1]=vec[1]/normm; vec2[2]=vec[2]/normm;
4902 const int *conn=_nodal_connec->getConstPointer();
4903 const int *connI=_nodal_connec_index->getConstPointer();
4904 const double *coo=_coords->getConstPointer();
4905 std::vector<double> addCoo;
4906 for(int i=0;i<ncells;i++)
4908 if(conn[connI[i]]==(int)INTERP_KERNEL::NORM_SEG2)
4910 if(cut3DCurve[i]==-2)
4912 int st=conn[connI[i]+1],endd=conn[connI[i]+2];
4913 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];
4914 double normm2=sqrt(vec3[0]*vec3[0]+vec3[1]*vec3[1]+vec3[2]*vec3[2]);
4915 double colin=std::abs((vec3[0]*vec2[0]+vec3[1]*vec2[1]+vec3[2]*vec2[2])/normm2);
4916 if(colin>eps)//if colin<=eps -> current SEG2 is colinear to the input plane
4918 const double *st2=coo+3*st;
4919 vec4[0]=st2[0]-origin[0]; vec4[1]=st2[1]-origin[1]; vec4[2]=st2[2]-origin[2];
4920 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]));
4921 if(pos>eps && pos<1-eps)
4923 int nNode=((int)addCoo.size())/3;
4924 vec4[0]=st2[0]+pos*vec3[0]; vec4[1]=st2[1]+pos*vec3[1]; vec4[2]=st2[2]+pos*vec3[2];
4925 addCoo.insert(addCoo.end(),vec4,vec4+3);
4926 cut3DCurve[i]=nnodes+nNode;
4932 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane : this method is only available for linear cell (NORM_SEG2) !");
4936 int newNbOfNodes=nnodes+((int)addCoo.size())/3;
4937 MCAuto<DataArrayDouble> coo2=DataArrayDouble::New();
4938 coo2->alloc(newNbOfNodes,3);
4939 double *tmp=coo2->getPointer();
4940 tmp=std::copy(_coords->begin(),_coords->end(),tmp);
4941 std::copy(addCoo.begin(),addCoo.end(),tmp);
4942 DataArrayDouble::SetArrayIn(coo2,_coords);
4947 * This method incarnates the policy 0 for MEDCouplingUMesh::buildExtrudedMesh method.
4948 * \param mesh1D is the input 1D mesh used for translation computation.
4949 * \return newCoords new coords filled by this method.
4951 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslation(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4953 int oldNbOfNodes=getNumberOfNodes();
4954 int nbOf1DCells=mesh1D->getNumberOfCells();
4955 int spaceDim=getSpaceDimension();
4956 DataArrayDouble *ret=DataArrayDouble::New();
4957 std::vector<bool> isQuads;
4958 int nbOfLevsInVec=isQuad?2*nbOf1DCells+1:nbOf1DCells+1;
4959 ret->alloc(oldNbOfNodes*nbOfLevsInVec,spaceDim);
4960 double *retPtr=ret->getPointer();
4961 const double *coords=getCoords()->getConstPointer();
4962 double *work=std::copy(coords,coords+spaceDim*oldNbOfNodes,retPtr);
4964 std::vector<double> c;
4968 for(int i=0;i<nbOf1DCells;i++)
4971 mesh1D->getNodeIdsOfCell(i,v);
4973 mesh1D->getCoordinatesOfNode(v[isQuad?2:1],c);
4974 mesh1D->getCoordinatesOfNode(v[0],c);
4975 std::transform(c.begin(),c.begin()+spaceDim,c.begin()+spaceDim,vec,std::minus<double>());
4976 for(int j=0;j<oldNbOfNodes;j++)
4977 work=std::transform(vec,vec+spaceDim,retPtr+spaceDim*(i*oldNbOfNodes+j),work,std::plus<double>());
4981 mesh1D->getCoordinatesOfNode(v[1],c);
4982 mesh1D->getCoordinatesOfNode(v[0],c);
4983 std::transform(c.begin(),c.begin()+spaceDim,c.begin()+spaceDim,vec,std::minus<double>());
4984 for(int j=0;j<oldNbOfNodes;j++)
4985 work=std::transform(vec,vec+spaceDim,retPtr+spaceDim*(i*oldNbOfNodes+j),work,std::plus<double>());
4988 ret->copyStringInfoFrom(*getCoords());
4993 * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4994 * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4995 * \return newCoords new coords filled by this method.
4997 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4999 if(mesh1D->getSpaceDimension()==2)
5000 return fillExtCoordsUsingTranslAndAutoRotation2D(mesh1D,isQuad);
5001 if(mesh1D->getSpaceDimension()==3)
5002 return fillExtCoordsUsingTranslAndAutoRotation3D(mesh1D,isQuad);
5003 throw INTERP_KERNEL::Exception("Not implemented rotation and translation alg. for spacedim other than 2 and 3 !");
5007 * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
5008 * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
5009 * \return newCoords new coords filled by this method.
5011 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D(const MEDCouplingUMesh *mesh1D, bool isQuad) const
5014 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D : not implemented for quadratic cells !");
5015 int oldNbOfNodes=getNumberOfNodes();
5016 int nbOf1DCells=mesh1D->getNumberOfCells();
5018 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D : impossible to detect any angle of rotation ! Change extrusion policy 1->0 !");
5019 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
5020 int nbOfLevsInVec=nbOf1DCells+1;
5021 ret->alloc(oldNbOfNodes*nbOfLevsInVec,2);
5022 double *retPtr=ret->getPointer();
5023 retPtr=std::copy(getCoords()->getConstPointer(),getCoords()->getConstPointer()+getCoords()->getNbOfElems(),retPtr);
5024 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
5025 MCAuto<DataArrayDouble> tmp2=getCoords()->deepCopy();
5026 tmp->setCoords(tmp2);
5027 const double *coo1D=mesh1D->getCoords()->getConstPointer();
5028 const int *conn1D=mesh1D->getNodalConnectivity()->getConstPointer();
5029 const int *connI1D=mesh1D->getNodalConnectivityIndex()->getConstPointer();
5030 for(int i=1;i<nbOfLevsInVec;i++)
5032 const double *begin=coo1D+2*conn1D[connI1D[i-1]+1];
5033 const double *end=coo1D+2*conn1D[connI1D[i-1]+2];
5034 const double *third=i+1<nbOfLevsInVec?coo1D+2*conn1D[connI1D[i]+2]:coo1D+2*conn1D[connI1D[i-2]+1];
5035 const double vec[2]={end[0]-begin[0],end[1]-begin[1]};
5036 tmp->translate(vec);
5037 double tmp3[2],radius,alpha,alpha0;
5038 const double *p0=i+1<nbOfLevsInVec?begin:third;
5039 const double *p1=i+1<nbOfLevsInVec?end:begin;
5040 const double *p2=i+1<nbOfLevsInVec?third:end;
5041 INTERP_KERNEL::EdgeArcCircle::GetArcOfCirclePassingThru(p0,p1,p2,tmp3,radius,alpha,alpha0);
5042 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]);
5043 double angle=acos(cosangle/(radius*radius));
5044 tmp->rotate(end,0,angle);
5045 retPtr=std::copy(tmp2->getConstPointer(),tmp2->getConstPointer()+tmp2->getNbOfElems(),retPtr);
5051 * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
5052 * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
5053 * \return newCoords new coords filled by this method.
5055 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D(const MEDCouplingUMesh *mesh1D, bool isQuad) const
5058 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D : not implemented for quadratic cells !");
5059 int oldNbOfNodes=getNumberOfNodes();
5060 int nbOf1DCells=mesh1D->getNumberOfCells();
5062 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D : impossible to detect any angle of rotation ! Change extrusion policy 1->0 !");
5063 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
5064 int nbOfLevsInVec=nbOf1DCells+1;
5065 ret->alloc(oldNbOfNodes*nbOfLevsInVec,3);
5066 double *retPtr=ret->getPointer();
5067 retPtr=std::copy(getCoords()->getConstPointer(),getCoords()->getConstPointer()+getCoords()->getNbOfElems(),retPtr);
5068 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
5069 MCAuto<DataArrayDouble> tmp2=getCoords()->deepCopy();
5070 tmp->setCoords(tmp2);
5071 const double *coo1D=mesh1D->getCoords()->getConstPointer();
5072 const int *conn1D=mesh1D->getNodalConnectivity()->getConstPointer();
5073 const int *connI1D=mesh1D->getNodalConnectivityIndex()->getConstPointer();
5074 for(int i=1;i<nbOfLevsInVec;i++)
5076 const double *begin=coo1D+3*conn1D[connI1D[i-1]+1];
5077 const double *end=coo1D+3*conn1D[connI1D[i-1]+2];
5078 const double *third=i+1<nbOfLevsInVec?coo1D+3*conn1D[connI1D[i]+2]:coo1D+3*conn1D[connI1D[i-2]+1];
5079 const double vec[3]={end[0]-begin[0],end[1]-begin[1],end[2]-begin[2]};
5080 tmp->translate(vec);
5081 double tmp3[2],radius,alpha,alpha0;
5082 const double *p0=i+1<nbOfLevsInVec?begin:third;
5083 const double *p1=i+1<nbOfLevsInVec?end:begin;
5084 const double *p2=i+1<nbOfLevsInVec?third:end;
5085 double vecPlane[3]={
5086 (p1[1]-p0[1])*(p2[2]-p1[2])-(p1[2]-p0[2])*(p2[1]-p1[1]),
5087 (p1[2]-p0[2])*(p2[0]-p1[0])-(p1[0]-p0[0])*(p2[2]-p1[2]),
5088 (p1[0]-p0[0])*(p2[1]-p1[1])-(p1[1]-p0[1])*(p2[0]-p1[0]),
5090 double norm=sqrt(vecPlane[0]*vecPlane[0]+vecPlane[1]*vecPlane[1]+vecPlane[2]*vecPlane[2]);
5093 vecPlane[0]/=norm; vecPlane[1]/=norm; vecPlane[2]/=norm;
5094 double norm2=sqrt(vecPlane[0]*vecPlane[0]+vecPlane[1]*vecPlane[1]);
5095 double vec2[2]={vecPlane[1]/norm2,-vecPlane[0]/norm2};
5097 double c2=cos(asin(s2));
5099 {vec2[0]*vec2[0]*(1-c2)+c2, vec2[0]*vec2[1]*(1-c2), vec2[1]*s2},
5100 {vec2[0]*vec2[1]*(1-c2), vec2[1]*vec2[1]*(1-c2)+c2, -vec2[0]*s2},
5101 {-vec2[1]*s2, vec2[0]*s2, c2}
5103 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]};
5104 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]};
5105 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]};
5106 INTERP_KERNEL::EdgeArcCircle::GetArcOfCirclePassingThru(p0r,p1r,p2r,tmp3,radius,alpha,alpha0);
5107 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]);
5108 double angle=acos(cosangle/(radius*radius));
5109 tmp->rotate(end,vecPlane,angle);
5111 retPtr=std::copy(tmp2->getConstPointer(),tmp2->getConstPointer()+tmp2->getNbOfElems(),retPtr);
5117 * This method is private because not easy to use for end user. This method is const contrary to
5118 * MEDCouplingUMesh::buildExtrudedMesh method because this->_coords are expected to contain
5119 * the coords sorted slice by slice.
5120 * \param isQuad specifies presence of quadratic cells.
5122 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMeshFromThisLowLev(int nbOfNodesOf1Lev, bool isQuad) const
5124 int nbOf1DCells(getNumberOfNodes()/nbOfNodesOf1Lev-1);
5125 int nbOf2DCells(getNumberOfCells());
5126 int nbOf3DCells(nbOf2DCells*nbOf1DCells);
5127 MEDCouplingUMesh *ret(MEDCouplingUMesh::New("Extruded",getMeshDimension()+1));
5128 const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5129 MCAuto<DataArrayInt> newConn(DataArrayInt::New()),newConnI(DataArrayInt::New());
5130 newConnI->alloc(nbOf3DCells+1,1);
5131 int *newConnIPtr(newConnI->getPointer());
5133 std::vector<int> newc;
5134 for(int j=0;j<nbOf2DCells;j++)
5136 AppendExtrudedCell(conn+connI[j],conn+connI[j+1],nbOfNodesOf1Lev,isQuad,newc);
5137 *newConnIPtr++=(int)newc.size();
5139 newConn->alloc((int)(newc.size())*nbOf1DCells,1);
5140 int *newConnPtr(newConn->getPointer());
5141 int deltaPerLev(isQuad?2*nbOfNodesOf1Lev:nbOfNodesOf1Lev);
5142 newConnIPtr=newConnI->getPointer();
5143 for(int iz=0;iz<nbOf1DCells;iz++)
5146 std::transform(newConnIPtr+1,newConnIPtr+1+nbOf2DCells,newConnIPtr+1+iz*nbOf2DCells,std::bind2nd(std::plus<int>(),newConnIPtr[iz*nbOf2DCells]));
5147 const int *posOfTypeOfCell(newConnIPtr);
5148 for(std::vector<int>::const_iterator iter=newc.begin();iter!=newc.end();iter++,newConnPtr++)
5150 int icell((int)(iter-newc.begin()));//std::distance unfortunately cannot been called here in C++98
5151 if(icell!=*posOfTypeOfCell)
5154 *newConnPtr=(*iter)+iz*deltaPerLev;
5165 ret->setConnectivity(newConn,newConnI,true);
5166 ret->setCoords(getCoords());
5171 * Checks if \a this mesh is constituted by only quadratic cells.
5172 * \return bool - \c true if there are only quadratic cells in \a this mesh.
5173 * \throw If the coordinates array is not set.
5174 * \throw If the nodal connectivity of cells is not defined.
5176 bool MEDCouplingUMesh::isFullyQuadratic() const
5178 checkFullyDefined();
5180 int nbOfCells=getNumberOfCells();
5181 for(int i=0;i<nbOfCells && ret;i++)
5183 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5184 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5185 ret=cm.isQuadratic();
5191 * Checks if \a this mesh includes any quadratic cell.
5192 * \return bool - \c true if there is at least one quadratic cells in \a this mesh.
5193 * \throw If the coordinates array is not set.
5194 * \throw If the nodal connectivity of cells is not defined.
5196 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
5198 checkFullyDefined();
5200 int nbOfCells=getNumberOfCells();
5201 for(int i=0;i<nbOfCells && !ret;i++)
5203 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5204 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5205 ret=cm.isQuadratic();
5211 * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
5212 * this mesh, it remains unchanged.
5213 * \throw If the coordinates array is not set.
5214 * \throw If the nodal connectivity of cells is not defined.
5216 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
5218 checkFullyDefined();
5219 int nbOfCells=getNumberOfCells();
5221 const int *iciptr=_nodal_connec_index->getConstPointer();
5222 for(int i=0;i<nbOfCells;i++)
5224 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5225 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5226 if(cm.isQuadratic())
5228 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
5229 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
5230 if(!cml.isDynamic())
5231 delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
5233 delta+=(iciptr[i+1]-iciptr[i]-1)/2;
5238 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5239 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5240 const int *icptr=_nodal_connec->getConstPointer();
5241 newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
5242 newConnI->alloc(nbOfCells+1,1);
5243 int *ocptr=newConn->getPointer();
5244 int *ociptr=newConnI->getPointer();
5247 for(int i=0;i<nbOfCells;i++,ociptr++)
5249 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
5250 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5251 if(!cm.isQuadratic())
5253 _types.insert(type);
5254 ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
5255 ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
5259 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
5260 _types.insert(typel);
5261 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
5262 int newNbOfNodes=cml.getNumberOfNodes();
5264 newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
5265 *ocptr++=(int)typel;
5266 ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
5267 ociptr[1]=ociptr[0]+newNbOfNodes+1;
5270 setConnectivity(newConn,newConnI,false);
5274 * This method converts all linear cell in \a this to quadratic one.
5275 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
5276 * 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)
5277 * 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.
5278 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
5279 * end of the existing coordinates.
5281 * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
5282 * corresponding quadratic cells. 1 is those creating the 'most' complex.
5283 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5285 * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
5287 * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
5289 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
5291 DataArrayInt *conn=0,*connI=0;
5292 DataArrayDouble *coords=0;
5293 std::set<INTERP_KERNEL::NormalizedCellType> types;
5294 checkFullyDefined();
5295 MCAuto<DataArrayInt> ret,connSafe,connISafe;
5296 MCAuto<DataArrayDouble> coordsSafe;
5297 int meshDim=getMeshDimension();
5298 switch(conversionType)
5304 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
5305 connSafe=conn; connISafe=connI; coordsSafe=coords;
5308 ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
5309 connSafe=conn; connISafe=connI; coordsSafe=coords;
5312 ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
5313 connSafe=conn; connISafe=connI; coordsSafe=coords;
5316 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
5324 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
5325 connSafe=conn; connISafe=connI; coordsSafe=coords;
5328 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
5329 connSafe=conn; connISafe=connI; coordsSafe=coords;
5332 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
5333 connSafe=conn; connISafe=connI; coordsSafe=coords;
5336 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
5341 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
5343 setConnectivity(connSafe,connISafe,false);
5345 setCoords(coordsSafe);
5350 * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
5351 * so that the number of cells remains the same. Quadratic faces are converted to
5352 * polygons. This method works only for 2D meshes in
5353 * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
5354 * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
5355 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5356 * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
5357 * a polylinized edge constituting the input polygon.
5358 * \throw If the coordinates array is not set.
5359 * \throw If the nodal connectivity of cells is not defined.
5360 * \throw If \a this->getMeshDimension() != 2.
5361 * \throw If \a this->getSpaceDimension() != 2.
5363 void MEDCouplingUMesh::tessellate2D(double eps)
5365 int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
5367 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
5371 return tessellate2DCurveInternal(eps);
5373 return tessellate2DInternal(eps);
5375 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
5379 * Tessellates \a this 1D mesh in 2D space by dividing not straight quadratic edges.
5380 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5381 * \param [in] eps - specifies the maximal angle (in radian) between 2 sub-edges of
5382 * a sub-divided edge.
5383 * \throw If the coordinates array is not set.
5384 * \throw If the nodal connectivity of cells is not defined.
5385 * \throw If \a this->getMeshDimension() != 1.
5386 * \throw If \a this->getSpaceDimension() != 2.
5391 * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
5392 * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
5393 * The nodes to be added in those 2D cells are defined by the pair of \a nodeIdsToAdd and \a nodeIdsIndexToAdd.
5394 * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
5395 * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
5396 * This method can be seen as the opposite method of colinearize2D.
5397 * 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
5398 * to avoid to modify the numbering of existing nodes.
5400 * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
5401 * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
5402 * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
5403 * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
5404 * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
5405 * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
5406 * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
5408 * \sa buildDescendingConnectivity2
5410 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayInt *nodeIdsToAdd, const DataArrayInt *nodeIdsIndexToAdd, const DataArrayInt *edgeIdsToBeSplit,
5411 const MEDCouplingUMesh *mesh1Desc, const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *revDesc, const DataArrayInt *revDescI)
5413 if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
5414 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
5415 nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
5416 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
5417 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
5418 if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
5419 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
5420 //DataArrayInt *out0(0),*outi0(0);
5421 //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
5422 //MCAuto<DataArrayInt> out0s(out0),outi0s(outi0);
5423 //out0s=out0s->buildUnique(); out0s->sort(true);
5428 * Implementes \a conversionType 0 for meshes with meshDim = 1, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5429 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5430 * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5432 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic1D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5434 MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5435 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5436 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5437 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5438 int nbOfCells=getNumberOfCells();
5439 int nbOfNodes=getNumberOfNodes();
5440 const int *cPtr=_nodal_connec->getConstPointer();
5441 const int *icPtr=_nodal_connec_index->getConstPointer();
5442 int lastVal=0,offset=nbOfNodes;
5443 for(int i=0;i<nbOfCells;i++,icPtr++)
5445 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5446 if(type==INTERP_KERNEL::NORM_SEG2)
5448 types.insert(INTERP_KERNEL::NORM_SEG3);
5449 newConn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG3);
5450 newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[0]+3);
5451 newConn->pushBackSilent(offset++);
5453 newConnI->pushBackSilent(lastVal);
5454 ret->pushBackSilent(i);
5459 lastVal+=(icPtr[1]-icPtr[0]);
5460 newConnI->pushBackSilent(lastVal);
5461 newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5464 MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5465 coords=DataArrayDouble::Aggregate(getCoords(),tmp); conn=newConn.retn(); connI=newConnI.retn();
5469 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
5471 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5472 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5473 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5475 const int *descPtr(desc->begin()),*descIPtr(descI->begin());
5476 DataArrayInt *conn1D=0,*conn1DI=0;
5477 std::set<INTERP_KERNEL::NormalizedCellType> types1D;
5478 DataArrayDouble *coordsTmp=0;
5479 MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=0;
5480 MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5481 MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5482 const int *c1DPtr=conn1D->begin();
5483 const int *c1DIPtr=conn1DI->begin();
5484 int nbOfCells=getNumberOfCells();
5485 const int *cPtr=_nodal_connec->getConstPointer();
5486 const int *icPtr=_nodal_connec_index->getConstPointer();
5488 for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++)
5490 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5491 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5492 if(!cm.isQuadratic())
5494 INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType();
5495 types.insert(typ2); newConn->pushBackSilent(typ2);
5496 newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5497 for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5498 newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5499 lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0]);
5500 newConnI->pushBackSilent(lastVal);
5501 ret->pushBackSilent(i);
5506 lastVal+=(icPtr[1]-icPtr[0]);
5507 newConnI->pushBackSilent(lastVal);
5508 newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5511 conn=newConn.retn(); connI=newConnI.retn(); coords=coordsTmpSafe.retn();
5516 * Implementes \a conversionType 0 for meshes with meshDim = 2, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5517 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5518 * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5520 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic2D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5522 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5523 MCAuto<MEDCouplingUMesh> m1D=buildDescendingConnectivity(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5524 return convertLinearCellsToQuadratic2DAnd3D0(m1D,desc,descI,conn,connI,coords,types);
5527 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic2D1(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5529 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5530 MCAuto<MEDCouplingUMesh> m1D=buildDescendingConnectivity(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5532 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5533 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5534 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5536 MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5537 const int *descPtr(desc->begin()),*descIPtr(descI->begin());
5538 DataArrayInt *conn1D=0,*conn1DI=0;
5539 std::set<INTERP_KERNEL::NormalizedCellType> types1D;
5540 DataArrayDouble *coordsTmp=0;
5541 MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=0;
5542 MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5543 MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5544 const int *c1DPtr=conn1D->begin();
5545 const int *c1DIPtr=conn1DI->begin();
5546 int nbOfCells=getNumberOfCells();
5547 const int *cPtr=_nodal_connec->getConstPointer();
5548 const int *icPtr=_nodal_connec_index->getConstPointer();
5549 int lastVal=0,offset=coordsTmpSafe->getNumberOfTuples();
5550 for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++)
5552 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5553 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5554 if(!cm.isQuadratic())
5556 INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType2();
5557 types.insert(typ2); newConn->pushBackSilent(typ2);
5558 newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5559 for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5560 newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5561 newConn->pushBackSilent(offset+ret->getNumberOfTuples());
5562 lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0])+1;
5563 newConnI->pushBackSilent(lastVal);
5564 ret->pushBackSilent(i);
5569 lastVal+=(icPtr[1]-icPtr[0]);
5570 newConnI->pushBackSilent(lastVal);
5571 newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5574 MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5575 coords=DataArrayDouble::Aggregate(coordsTmpSafe,tmp); conn=newConn.retn(); connI=newConnI.retn();
5580 * Implementes \a conversionType 0 for meshes with meshDim = 3, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5581 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5582 * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5584 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic3D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5586 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5587 MCAuto<MEDCouplingUMesh> m1D=explode3DMeshTo1D(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5588 return convertLinearCellsToQuadratic2DAnd3D0(m1D,desc,descI,conn,connI,coords,types);
5591 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic3D1(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5593 MCAuto<DataArrayInt> desc2(DataArrayInt::New()),desc2I(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5594 MCAuto<MEDCouplingUMesh> m2D=buildDescendingConnectivityGen<MinusOneSonsGeneratorBiQuadratic>(desc2,desc2I,tmp2,tmp3,MEDCouplingFastNbrer); tmp2=0; tmp3=0;
5595 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),desc1I(DataArrayInt::New()),tmp4(DataArrayInt::New()),tmp5(DataArrayInt::New());
5596 MCAuto<MEDCouplingUMesh> m1D=explode3DMeshTo1D(desc1,desc1I,tmp4,tmp5); tmp4=0; tmp5=0;
5598 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5599 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5600 MCAuto<DataArrayInt> ret=DataArrayInt::New(),ret2=DataArrayInt::New(); ret->alloc(0,1); ret2->alloc(0,1);
5602 MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5603 const int *descPtr(desc1->begin()),*descIPtr(desc1I->begin()),*desc2Ptr(desc2->begin()),*desc2IPtr(desc2I->begin());
5604 DataArrayInt *conn1D=0,*conn1DI=0,*conn2D=0,*conn2DI=0;
5605 std::set<INTERP_KERNEL::NormalizedCellType> types1D,types2D;
5606 DataArrayDouble *coordsTmp=0,*coordsTmp2=0;
5607 MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=DataArrayInt::New(); ret1D->alloc(0,1);
5608 MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5609 MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5610 MCAuto<DataArrayInt> ret2D=m2D->convertLinearCellsToQuadratic2D1(conn2D,conn2DI,coordsTmp2,types2D); ret2D=DataArrayInt::New(); ret2D->alloc(0,1);
5611 MCAuto<DataArrayDouble> coordsTmp2Safe(coordsTmp2);
5612 MCAuto<DataArrayInt> conn2DSafe(conn2D),conn2DISafe(conn2DI);
5613 const int *c1DPtr=conn1D->begin(),*c1DIPtr=conn1DI->begin(),*c2DPtr=conn2D->begin(),*c2DIPtr=conn2DI->begin();
5614 int nbOfCells=getNumberOfCells();
5615 const int *cPtr=_nodal_connec->getConstPointer();
5616 const int *icPtr=_nodal_connec_index->getConstPointer();
5617 int lastVal=0,offset=coordsTmpSafe->getNumberOfTuples();
5618 for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++,desc2IPtr++)
5620 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5621 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5622 if(!cm.isQuadratic())
5624 INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType2();
5625 if(typ2==INTERP_KERNEL::NORM_ERROR)
5627 std::ostringstream oss; oss << "MEDCouplingUMesh::convertLinearCellsToQuadratic3D1 : On cell #" << i << " the linear cell type does not support advanced quadratization !";
5628 throw INTERP_KERNEL::Exception(oss.str());
5630 types.insert(typ2); newConn->pushBackSilent(typ2);
5631 newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5632 for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5633 newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5634 for(const int *d=desc2Ptr+desc2IPtr[0];d!=desc2Ptr+desc2IPtr[1];d++)
5636 int nodeId2=c2DPtr[c2DIPtr[(*d)+1]-1];
5637 int tmpPos=newConn->getNumberOfTuples();
5638 newConn->pushBackSilent(nodeId2);
5639 ret2D->pushBackSilent(nodeId2); ret1D->pushBackSilent(tmpPos);
5641 newConn->pushBackSilent(offset+ret->getNumberOfTuples());
5642 lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0])+(desc2IPtr[1]-desc2IPtr[0])+1;
5643 newConnI->pushBackSilent(lastVal);
5644 ret->pushBackSilent(i);
5649 lastVal+=(icPtr[1]-icPtr[0]);
5650 newConnI->pushBackSilent(lastVal);
5651 newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5654 MCAuto<DataArrayInt> diffRet2D=ret2D->getDifferentValues();
5655 MCAuto<DataArrayInt> o2nRet2D=diffRet2D->invertArrayN2O2O2N(coordsTmp2Safe->getNumberOfTuples());
5656 coordsTmp2Safe=coordsTmp2Safe->selectByTupleId(diffRet2D->begin(),diffRet2D->end());
5657 MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5658 std::vector<const DataArrayDouble *> v(3); v[0]=coordsTmpSafe; v[1]=coordsTmp2Safe; v[2]=tmp;
5659 int *c=newConn->getPointer();
5660 const int *cI(newConnI->begin());
5661 for(const int *elt=ret1D->begin();elt!=ret1D->end();elt++)
5662 c[*elt]=o2nRet2D->getIJ(c[*elt],0)+offset;
5663 offset=coordsTmp2Safe->getNumberOfTuples();
5664 for(const int *elt=ret->begin();elt!=ret->end();elt++)
5665 c[cI[(*elt)+1]-1]+=offset;
5666 coords=DataArrayDouble::Aggregate(v); conn=newConn.retn(); connI=newConnI.retn();
5671 * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
5672 * In addition, returns an array mapping new cells to old ones. <br>
5673 * This method typically increases the number of cells in \a this mesh
5674 * but the number of nodes remains \b unchanged.
5675 * That's why the 3D splitting policies
5676 * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
5677 * \param [in] policy - specifies a pattern used for splitting.
5678 * The semantic of \a policy is:
5679 * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
5680 * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
5681 * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8 into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
5682 * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8 into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
5685 * \return DataArrayInt * - a new instance of DataArrayInt holding, for each new cell,
5686 * an id of old cell producing it. The caller is to delete this array using
5687 * decrRef() as it is no more needed.
5689 * \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
5690 * \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
5691 * and \a this->getMeshDimension() != 3.
5692 * \throw If \a policy is not one of the four discussed above.
5693 * \throw If the nodal connectivity of cells is not defined.
5694 * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
5696 DataArrayInt *MEDCouplingUMesh::simplexize(int policy)
5701 return simplexizePol0();
5703 return simplexizePol1();
5704 case (int) INTERP_KERNEL::PLANAR_FACE_5:
5705 return simplexizePlanarFace5();
5706 case (int) INTERP_KERNEL::PLANAR_FACE_6:
5707 return simplexizePlanarFace6();
5709 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)");
5714 * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
5715 * - 1D: INTERP_KERNEL::NORM_SEG2
5716 * - 2D: INTERP_KERNEL::NORM_TRI3
5717 * - 3D: INTERP_KERNEL::NORM_TETRA4.
5719 * This method is useful for users that need to use P1 field services as
5720 * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
5721 * All these methods need mesh support containing only simplex cells.
5722 * \return bool - \c true if there are only simplex cells in \a this mesh.
5723 * \throw If the coordinates array is not set.
5724 * \throw If the nodal connectivity of cells is not defined.
5725 * \throw If \a this->getMeshDimension() < 1.
5727 bool MEDCouplingUMesh::areOnlySimplexCells() const
5729 checkFullyDefined();
5730 int mdim=getMeshDimension();
5731 if(mdim<1 || mdim>3)
5732 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
5733 int nbCells=getNumberOfCells();
5734 const int *conn=_nodal_connec->getConstPointer();
5735 const int *connI=_nodal_connec_index->getConstPointer();
5736 for(int i=0;i<nbCells;i++)
5738 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5746 * This method implements policy 0 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5748 DataArrayInt *MEDCouplingUMesh::simplexizePol0()
5750 checkConnectivityFullyDefined();
5751 if(getMeshDimension()!=2)
5752 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePol0 : this policy is only available for mesh with meshdim == 2 !");
5753 int nbOfCells=getNumberOfCells();
5754 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5755 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_QUAD4);
5756 ret->alloc(nbOfCells+nbOfCutCells,1);
5757 if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5758 int *retPt=ret->getPointer();
5759 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5760 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5761 newConnI->alloc(nbOfCells+nbOfCutCells+1,1);
5762 newConn->alloc(getNodalConnectivityArrayLen()+3*nbOfCutCells,1);
5763 int *pt=newConn->getPointer();
5764 int *ptI=newConnI->getPointer();
5766 const int *oldc=_nodal_connec->getConstPointer();
5767 const int *ci=_nodal_connec_index->getConstPointer();
5768 for(int i=0;i<nbOfCells;i++,ci++)
5770 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_QUAD4)
5772 const int tmp[8]={(int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+2],oldc[ci[0]+3],
5773 (int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+3],oldc[ci[0]+4]};
5774 pt=std::copy(tmp,tmp+8,pt);
5783 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5784 ptI[1]=ptI[0]+ci[1]-ci[0];
5789 _nodal_connec->decrRef();
5790 _nodal_connec=newConn.retn();
5791 _nodal_connec_index->decrRef();
5792 _nodal_connec_index=newConnI.retn();
5799 * This method implements policy 1 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5801 DataArrayInt *MEDCouplingUMesh::simplexizePol1()
5803 checkConnectivityFullyDefined();
5804 if(getMeshDimension()!=2)
5805 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePol0 : this policy is only available for mesh with meshdim == 2 !");
5806 int nbOfCells=getNumberOfCells();
5807 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5808 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_QUAD4);
5809 ret->alloc(nbOfCells+nbOfCutCells,1);
5810 if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5811 int *retPt=ret->getPointer();
5812 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5813 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5814 newConnI->alloc(nbOfCells+nbOfCutCells+1,1);
5815 newConn->alloc(getNodalConnectivityArrayLen()+3*nbOfCutCells,1);
5816 int *pt=newConn->getPointer();
5817 int *ptI=newConnI->getPointer();
5819 const int *oldc=_nodal_connec->getConstPointer();
5820 const int *ci=_nodal_connec_index->getConstPointer();
5821 for(int i=0;i<nbOfCells;i++,ci++)
5823 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_QUAD4)
5825 const int tmp[8]={(int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+2],oldc[ci[0]+4],
5826 (int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+2],oldc[ci[0]+3],oldc[ci[0]+4]};
5827 pt=std::copy(tmp,tmp+8,pt);
5836 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5837 ptI[1]=ptI[0]+ci[1]-ci[0];
5842 _nodal_connec->decrRef();
5843 _nodal_connec=newConn.retn();
5844 _nodal_connec_index->decrRef();
5845 _nodal_connec_index=newConnI.retn();
5852 * This method implements policy INTERP_KERNEL::PLANAR_FACE_5 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5854 DataArrayInt *MEDCouplingUMesh::simplexizePlanarFace5()
5856 checkConnectivityFullyDefined();
5857 if(getMeshDimension()!=3)
5858 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePlanarFace5 : this policy is only available for mesh with meshdim == 3 !");
5859 int nbOfCells=getNumberOfCells();
5860 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5861 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_HEXA8);
5862 ret->alloc(nbOfCells+4*nbOfCutCells,1);
5863 if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5864 int *retPt=ret->getPointer();
5865 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5866 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5867 newConnI->alloc(nbOfCells+4*nbOfCutCells+1,1);
5868 newConn->alloc(getNodalConnectivityArrayLen()+16*nbOfCutCells,1);//21
5869 int *pt=newConn->getPointer();
5870 int *ptI=newConnI->getPointer();
5872 const int *oldc=_nodal_connec->getConstPointer();
5873 const int *ci=_nodal_connec_index->getConstPointer();
5874 for(int i=0;i<nbOfCells;i++,ci++)
5876 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_HEXA8)
5878 for(int j=0;j<5;j++,pt+=5,ptI++)
5880 pt[0]=(int)INTERP_KERNEL::NORM_TETRA4;
5881 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];
5888 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5889 ptI[1]=ptI[0]+ci[1]-ci[0];
5894 _nodal_connec->decrRef();
5895 _nodal_connec=newConn.retn();
5896 _nodal_connec_index->decrRef();
5897 _nodal_connec_index=newConnI.retn();
5904 * This method implements policy INTERP_KERNEL::PLANAR_FACE_6 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5906 DataArrayInt *MEDCouplingUMesh::simplexizePlanarFace6()
5908 checkConnectivityFullyDefined();
5909 if(getMeshDimension()!=3)
5910 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePlanarFace6 : this policy is only available for mesh with meshdim == 3 !");
5911 int nbOfCells=getNumberOfCells();
5912 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5913 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_HEXA8);
5914 ret->alloc(nbOfCells+5*nbOfCutCells,1);
5915 if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5916 int *retPt=ret->getPointer();
5917 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5918 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5919 newConnI->alloc(nbOfCells+5*nbOfCutCells+1,1);
5920 newConn->alloc(getNodalConnectivityArrayLen()+21*nbOfCutCells,1);
5921 int *pt=newConn->getPointer();
5922 int *ptI=newConnI->getPointer();
5924 const int *oldc=_nodal_connec->getConstPointer();
5925 const int *ci=_nodal_connec_index->getConstPointer();
5926 for(int i=0;i<nbOfCells;i++,ci++)
5928 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_HEXA8)
5930 for(int j=0;j<6;j++,pt+=5,ptI++)
5932 pt[0]=(int)INTERP_KERNEL::NORM_TETRA4;
5933 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];
5940 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5941 ptI[1]=ptI[0]+ci[1]-ci[0];
5946 _nodal_connec->decrRef();
5947 _nodal_connec=newConn.retn();
5948 _nodal_connec_index->decrRef();
5949 _nodal_connec_index=newConnI.retn();
5956 * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
5957 * so that the number of cells remains the same. Quadratic faces are converted to
5958 * polygons. This method works only for 2D meshes in
5959 * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
5960 * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
5961 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5962 * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
5963 * a polylinized edge constituting the input polygon.
5964 * \throw If the coordinates array is not set.
5965 * \throw If the nodal connectivity of cells is not defined.
5966 * \throw If \a this->getMeshDimension() != 2.
5967 * \throw If \a this->getSpaceDimension() != 2.
5969 void MEDCouplingUMesh::tessellate2DInternal(double eps)
5971 checkFullyDefined();
5972 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
5973 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DInternal works on umeshes with meshdim equal to 2 and spaceDim equal to 2 too!");
5974 double epsa=fabs(eps);
5975 if(epsa<std::numeric_limits<double>::min())
5976 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 !");
5977 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
5978 MCAuto<MEDCouplingUMesh> mDesc(buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1));
5979 revDesc1=0; revDescIndx1=0;
5980 mDesc->tessellate2D(eps);
5981 subDivide2DMesh(mDesc->_nodal_connec->getConstPointer(),mDesc->_nodal_connec_index->getConstPointer(),desc1->getConstPointer(),descIndx1->getConstPointer());
5982 setCoords(mDesc->getCoords());
5986 * Tessellates \a this 1D mesh in 2D space by dividing not straight quadratic edges.
5987 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5988 * \param [in] eps - specifies the maximal angle (in radian) between 2 sub-edges of
5989 * a sub-divided edge.
5990 * \throw If the coordinates array is not set.
5991 * \throw If the nodal connectivity of cells is not defined.
5992 * \throw If \a this->getMeshDimension() != 1.
5993 * \throw If \a this->getSpaceDimension() != 2.
5995 void MEDCouplingUMesh::tessellate2DCurveInternal(double eps)
5997 checkFullyDefined();
5998 if(getMeshDimension()!=1 || getSpaceDimension()!=2)
5999 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DCurveInternal works on umeshes with meshdim equal to 1 and spaceDim equal to 2 too!");
6000 double epsa=fabs(eps);
6001 if(epsa<std::numeric_limits<double>::min())
6002 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 !");
6003 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=1.e-10;
6004 int nbCells=getNumberOfCells();
6005 int nbNodes=getNumberOfNodes();
6006 const int *conn=_nodal_connec->getConstPointer();
6007 const int *connI=_nodal_connec_index->getConstPointer();
6008 const double *coords=_coords->getConstPointer();
6009 std::vector<double> addCoo;
6010 std::vector<int> newConn;//no direct DataArrayInt because interface with Geometric2D
6011 MCAuto<DataArrayInt> newConnI(DataArrayInt::New());
6012 newConnI->alloc(nbCells+1,1);
6013 int *newConnIPtr=newConnI->getPointer();
6016 INTERP_KERNEL::Node *tmp2[3];
6017 std::set<INTERP_KERNEL::NormalizedCellType> types;
6018 for(int i=0;i<nbCells;i++,newConnIPtr++)
6020 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6021 if(cm.isQuadratic())
6022 {//assert(connI[i+1]-connI[i]-1==3)
6023 tmp1[0]=conn[connI[i]+1+0]; tmp1[1]=conn[connI[i]+1+1]; tmp1[2]=conn[connI[i]+1+2];
6024 tmp2[0]=new INTERP_KERNEL::Node(coords[2*tmp1[0]],coords[2*tmp1[0]+1]);
6025 tmp2[1]=new INTERP_KERNEL::Node(coords[2*tmp1[1]],coords[2*tmp1[1]+1]);
6026 tmp2[2]=new INTERP_KERNEL::Node(coords[2*tmp1[2]],coords[2*tmp1[2]+1]);
6027 INTERP_KERNEL::EdgeArcCircle *eac=INTERP_KERNEL::EdgeArcCircle::BuildFromNodes(tmp2[0],tmp2[2],tmp2[1]);
6030 eac->tesselate(tmp1,nbNodes,epsa,newConn,addCoo);
6031 types.insert((INTERP_KERNEL::NormalizedCellType)newConn[newConnIPtr[0]]);
6033 newConnIPtr[1]=(int)newConn.size();
6037 types.insert(INTERP_KERNEL::NORM_SEG2);
6038 newConn.push_back(INTERP_KERNEL::NORM_SEG2);
6039 newConn.insert(newConn.end(),conn+connI[i]+1,conn+connI[i]+3);
6040 newConnIPtr[1]=newConnIPtr[0]+3;
6045 types.insert((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6046 newConn.insert(newConn.end(),conn+connI[i],conn+connI[i+1]);
6047 newConnIPtr[1]=newConnIPtr[0]+3;
6050 if(addCoo.empty() && ((int)newConn.size())==_nodal_connec->getNumberOfTuples())//nothing happens during tessellation : no update needed
6053 DataArrayInt::SetArrayIn(newConnI,_nodal_connec_index);
6054 MCAuto<DataArrayInt> newConnArr=DataArrayInt::New();
6055 newConnArr->alloc((int)newConn.size(),1);
6056 std::copy(newConn.begin(),newConn.end(),newConnArr->getPointer());
6057 DataArrayInt::SetArrayIn(newConnArr,_nodal_connec);
6058 MCAuto<DataArrayDouble> newCoords=DataArrayDouble::New();
6059 newCoords->alloc(nbNodes+((int)addCoo.size())/2,2);
6060 double *work=std::copy(_coords->begin(),_coords->end(),newCoords->getPointer());
6061 std::copy(addCoo.begin(),addCoo.end(),work);
6062 DataArrayDouble::SetArrayIn(newCoords,_coords);
6067 * 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.
6068 * This method completly ignore coordinates.
6069 * \param nodeSubdived is the nodal connectivity of subdivision of edges
6070 * \param nodeIndxSubdived is the nodal connectivity index of subdivision of edges
6071 * \param desc is descending connectivity in format specified in MEDCouplingUMesh::buildDescendingConnectivity2
6072 * \param descIndex is descending connectivity index in format specified in MEDCouplingUMesh::buildDescendingConnectivity2
6074 void MEDCouplingUMesh::subDivide2DMesh(const int *nodeSubdived, const int *nodeIndxSubdived, const int *desc, const int *descIndex)
6076 checkFullyDefined();
6077 if(getMeshDimension()!=2)
6078 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::subDivide2DMesh : works only on umesh with meshdim==2 !");
6079 int nbOfCells=getNumberOfCells();
6080 int *connI=_nodal_connec_index->getPointer();
6082 for(int i=0;i<nbOfCells;i++,connI++)
6084 int offset=descIndex[i];
6085 int nbOfEdges=descIndex[i+1]-offset;
6087 bool ddirect=desc[offset+nbOfEdges-1]>0;
6088 int eedgeId=std::abs(desc[offset+nbOfEdges-1])-1;
6089 int ref=ddirect?nodeSubdived[nodeIndxSubdived[eedgeId+1]-1]:nodeSubdived[nodeIndxSubdived[eedgeId]+1];
6090 for(int j=0;j<nbOfEdges;j++)
6092 bool direct=desc[offset+j]>0;
6093 int edgeId=std::abs(desc[offset+j])-1;
6094 if(!INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodeSubdived[nodeIndxSubdived[edgeId]]).isQuadratic())
6096 int id1=nodeSubdived[nodeIndxSubdived[edgeId]+1];
6097 int id2=nodeSubdived[nodeIndxSubdived[edgeId+1]-1];
6098 int ref2=direct?id1:id2;
6101 int nbOfSubNodes=nodeIndxSubdived[edgeId+1]-nodeIndxSubdived[edgeId]-1;
6102 newConnLgth+=nbOfSubNodes-1;
6107 std::ostringstream oss; oss << "MEDCouplingUMesh::subDivide2DMesh : On polygon #" << i << " edgeid #" << j << " subedges mismatch : end subedge k!=start subedge k+1 !";
6108 throw INTERP_KERNEL::Exception(oss.str());
6113 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::subDivide2DMesh : this method only subdivides into linear edges !");
6116 newConnLgth++;//+1 is for cell type
6117 connI[1]=newConnLgth;
6120 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
6121 newConn->alloc(newConnLgth,1);
6122 int *work=newConn->getPointer();
6123 for(int i=0;i<nbOfCells;i++)
6125 *work++=INTERP_KERNEL::NORM_POLYGON;
6126 int offset=descIndex[i];
6127 int nbOfEdges=descIndex[i+1]-offset;
6128 for(int j=0;j<nbOfEdges;j++)
6130 bool direct=desc[offset+j]>0;
6131 int edgeId=std::abs(desc[offset+j])-1;
6133 work=std::copy(nodeSubdived+nodeIndxSubdived[edgeId]+1,nodeSubdived+nodeIndxSubdived[edgeId+1]-1,work);
6136 int nbOfSubNodes=nodeIndxSubdived[edgeId+1]-nodeIndxSubdived[edgeId]-1;
6137 std::reverse_iterator<const int *> it(nodeSubdived+nodeIndxSubdived[edgeId+1]);
6138 work=std::copy(it,it+nbOfSubNodes-1,work);
6142 DataArrayInt::SetArrayIn(newConn,_nodal_connec);
6145 _types.insert(INTERP_KERNEL::NORM_POLYGON);
6149 * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
6150 * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
6151 * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell. This method
6152 * does \b not perform geometrical checks and checks only nodal connectivity of cells,
6153 * so it can be useful to call mergeNodes() before calling this method.
6154 * \throw If \a this->getMeshDimension() <= 1.
6155 * \throw If the coordinates array is not set.
6156 * \throw If the nodal connectivity of cells is not defined.
6158 void MEDCouplingUMesh::convertDegeneratedCells()
6160 checkFullyDefined();
6161 if(getMeshDimension()<=1)
6162 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
6163 int nbOfCells=getNumberOfCells();
6166 int initMeshLgth=getNodalConnectivityArrayLen();
6167 int *conn=_nodal_connec->getPointer();
6168 int *index=_nodal_connec_index->getPointer();
6172 for(int i=0;i<nbOfCells;i++)
6174 lgthOfCurCell=index[i+1]-posOfCurCell;
6175 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
6177 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
6178 conn+newPos+1,newLgth);
6179 conn[newPos]=newType;
6181 posOfCurCell=index[i+1];
6184 if(newPos!=initMeshLgth)
6185 _nodal_connec->reAlloc(newPos);
6190 * Finds incorrectly oriented cells of this 2D mesh in 3D space.
6191 * A cell is considered to be oriented correctly if an angle between its
6192 * normal vector and a given vector is less than \c PI / \c 2.
6193 * \param [in] vec - 3 components of the vector specifying the correct orientation of
6195 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
6197 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
6198 * is not cleared before filling in.
6199 * \throw If \a this->getMeshDimension() != 2.
6200 * \throw If \a this->getSpaceDimension() != 3.
6202 * \if ENABLE_EXAMPLES
6203 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
6204 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
6207 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<int>& cells) const
6209 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6210 throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
6211 int nbOfCells=getNumberOfCells();
6212 const int *conn=_nodal_connec->getConstPointer();
6213 const int *connI=_nodal_connec_index->getConstPointer();
6214 const double *coordsPtr=_coords->getConstPointer();
6215 for(int i=0;i<nbOfCells;i++)
6217 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6218 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
6220 bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
6221 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6228 * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
6229 * considered to be oriented correctly if an angle between its normal vector and a
6230 * given vector is less than \c PI / \c 2.
6231 * \param [in] vec - 3 components of the vector specifying the correct orientation of
6233 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
6235 * \throw If \a this->getMeshDimension() != 2.
6236 * \throw If \a this->getSpaceDimension() != 3.
6238 * \if ENABLE_EXAMPLES
6239 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
6240 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
6243 * \sa changeOrientationOfCells
6245 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
6247 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6248 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
6249 int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
6250 const int *connI(_nodal_connec_index->getConstPointer());
6251 const double *coordsPtr(_coords->getConstPointer());
6252 bool isModified(false);
6253 for(int i=0;i<nbOfCells;i++)
6255 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6256 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
6258 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6259 bool isQuadratic(cm.isQuadratic());
6260 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6263 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6268 _nodal_connec->declareAsNew();
6273 * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
6275 * \sa orientCorrectly2DCells
6277 void MEDCouplingUMesh::changeOrientationOfCells()
6279 int mdim(getMeshDimension());
6280 if(mdim!=2 && mdim!=1)
6281 throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
6282 int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
6283 const int *connI(_nodal_connec_index->getConstPointer());
6286 for(int i=0;i<nbOfCells;i++)
6288 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6289 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6290 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6295 for(int i=0;i<nbOfCells;i++)
6297 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6298 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6299 cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6305 * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
6306 * oriented facets. The normal vector of the facet should point out of the cell.
6307 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
6308 * is not cleared before filling in.
6309 * \throw If \a this->getMeshDimension() != 3.
6310 * \throw If \a this->getSpaceDimension() != 3.
6311 * \throw If the coordinates array is not set.
6312 * \throw If the nodal connectivity of cells is not defined.
6314 * \if ENABLE_EXAMPLES
6315 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
6316 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
6319 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<int>& cells) const
6321 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6322 throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
6323 int nbOfCells=getNumberOfCells();
6324 const int *conn=_nodal_connec->getConstPointer();
6325 const int *connI=_nodal_connec_index->getConstPointer();
6326 const double *coordsPtr=_coords->getConstPointer();
6327 for(int i=0;i<nbOfCells;i++)
6329 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6330 if(type==INTERP_KERNEL::NORM_POLYHED)
6332 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6339 * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
6341 * \throw If \a this->getMeshDimension() != 3.
6342 * \throw If \a this->getSpaceDimension() != 3.
6343 * \throw If the coordinates array is not set.
6344 * \throw If the nodal connectivity of cells is not defined.
6345 * \throw If the reparation fails.
6347 * \if ENABLE_EXAMPLES
6348 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
6349 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
6351 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
6353 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
6355 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6356 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
6357 int nbOfCells=getNumberOfCells();
6358 int *conn=_nodal_connec->getPointer();
6359 const int *connI=_nodal_connec_index->getConstPointer();
6360 const double *coordsPtr=_coords->getConstPointer();
6361 for(int i=0;i<nbOfCells;i++)
6363 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6364 if(type==INTERP_KERNEL::NORM_POLYHED)
6368 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6369 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
6371 catch(INTERP_KERNEL::Exception& e)
6373 std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
6374 throw INTERP_KERNEL::Exception(oss.str());
6382 * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
6383 * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
6384 * according to which the first facet of the cell should be oriented to have the normal vector
6385 * pointing out of cell.
6386 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of fixed
6387 * cells. The caller is to delete this array using decrRef() as it is no more
6389 * \throw If \a this->getMeshDimension() != 3.
6390 * \throw If \a this->getSpaceDimension() != 3.
6391 * \throw If the coordinates array is not set.
6392 * \throw If the nodal connectivity of cells is not defined.
6394 * \if ENABLE_EXAMPLES
6395 * \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
6396 * \ref py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
6398 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
6400 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
6402 const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
6403 if(getMeshDimension()!=3)
6404 throw INTERP_KERNEL::Exception(msg);
6405 int spaceDim=getSpaceDimension();
6407 throw INTERP_KERNEL::Exception(msg);
6409 int nbOfCells=getNumberOfCells();
6410 int *conn=_nodal_connec->getPointer();
6411 const int *connI=_nodal_connec_index->getConstPointer();
6412 const double *coo=getCoords()->getConstPointer();
6413 MCAuto<DataArrayInt> cells(DataArrayInt::New()); cells->alloc(0,1);
6414 for(int i=0;i<nbOfCells;i++)
6416 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6417 if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
6419 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
6421 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
6422 cells->pushBackSilent(i);
6426 return cells.retn();
6430 * This method is a faster method to correct orientation of all 3D cells in \a this.
6431 * 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.
6432 * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
6434 * \return a newly allocated int array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
6435 * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
6437 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
6439 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6440 throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
6441 int nbOfCells=getNumberOfCells();
6442 int *conn=_nodal_connec->getPointer();
6443 const int *connI=_nodal_connec_index->getConstPointer();
6444 const double *coordsPtr=_coords->getConstPointer();
6445 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
6446 for(int i=0;i<nbOfCells;i++)
6448 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6451 case INTERP_KERNEL::NORM_TETRA4:
6453 if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6455 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
6456 ret->pushBackSilent(i);
6460 case INTERP_KERNEL::NORM_PYRA5:
6462 if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6464 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
6465 ret->pushBackSilent(i);
6469 case INTERP_KERNEL::NORM_PENTA6:
6470 case INTERP_KERNEL::NORM_HEXA8:
6471 case INTERP_KERNEL::NORM_HEXGP12:
6473 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6475 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
6476 ret->pushBackSilent(i);
6480 case INTERP_KERNEL::NORM_POLYHED:
6482 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6484 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
6485 ret->pushBackSilent(i);
6490 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 !");
6498 * This method has a sense for meshes with spaceDim==3 and meshDim==2.
6499 * If it is not the case an exception will be thrown.
6500 * This method is fast because the first cell of \a this is used to compute the plane.
6501 * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
6502 * \param pos output of size at least 3 used to store a point owned of searched plane.
6504 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
6506 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6507 throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
6508 const int *conn=_nodal_connec->getConstPointer();
6509 const int *connI=_nodal_connec_index->getConstPointer();
6510 const double *coordsPtr=_coords->getConstPointer();
6511 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
6512 std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
6516 * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
6517 * cells. Currently cells of the following types are treated:
6518 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
6519 * For a cell of other type an exception is thrown.
6520 * Space dimension of a 2D mesh can be either 2 or 3.
6521 * The Edge Ratio of a cell \f$t\f$ is:
6522 * \f$\frac{|t|_\infty}{|t|_0}\f$,
6523 * where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
6524 * the smallest edge lengths of \f$t\f$.
6525 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6526 * cells and one time, lying on \a this mesh. The caller is to delete this
6527 * field using decrRef() as it is no more needed.
6528 * \throw If the coordinates array is not set.
6529 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6530 * \throw If the connectivity data array has more than one component.
6531 * \throw If the connectivity data array has a named component.
6532 * \throw If the connectivity index data array has more than one component.
6533 * \throw If the connectivity index data array has a named component.
6534 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
6535 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
6536 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
6538 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
6540 checkConsistencyLight();
6541 int spaceDim=getSpaceDimension();
6542 int meshDim=getMeshDimension();
6543 if(spaceDim!=2 && spaceDim!=3)
6544 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
6545 if(meshDim!=2 && meshDim!=3)
6546 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
6547 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6549 int nbOfCells=getNumberOfCells();
6550 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6551 arr->alloc(nbOfCells,1);
6552 double *pt=arr->getPointer();
6553 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6554 const int *conn=_nodal_connec->getConstPointer();
6555 const int *connI=_nodal_connec_index->getConstPointer();
6556 const double *coo=_coords->getConstPointer();
6558 for(int i=0;i<nbOfCells;i++,pt++)
6560 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6563 case INTERP_KERNEL::NORM_TRI3:
6565 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
6566 *pt=INTERP_KERNEL::triEdgeRatio(tmp);
6569 case INTERP_KERNEL::NORM_QUAD4:
6571 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6572 *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
6575 case INTERP_KERNEL::NORM_TETRA4:
6577 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6578 *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
6582 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
6584 conn+=connI[i+1]-connI[i];
6586 ret->setName("EdgeRatio");
6587 ret->synchronizeTimeWithSupport();
6592 * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
6593 * cells. Currently cells of the following types are treated:
6594 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
6595 * For a cell of other type an exception is thrown.
6596 * Space dimension of a 2D mesh can be either 2 or 3.
6597 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6598 * cells and one time, lying on \a this mesh. The caller is to delete this
6599 * field using decrRef() as it is no more needed.
6600 * \throw If the coordinates array is not set.
6601 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6602 * \throw If the connectivity data array has more than one component.
6603 * \throw If the connectivity data array has a named component.
6604 * \throw If the connectivity index data array has more than one component.
6605 * \throw If the connectivity index data array has a named component.
6606 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
6607 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
6608 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
6610 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
6612 checkConsistencyLight();
6613 int spaceDim=getSpaceDimension();
6614 int meshDim=getMeshDimension();
6615 if(spaceDim!=2 && spaceDim!=3)
6616 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
6617 if(meshDim!=2 && meshDim!=3)
6618 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
6619 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6621 int nbOfCells=getNumberOfCells();
6622 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6623 arr->alloc(nbOfCells,1);
6624 double *pt=arr->getPointer();
6625 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6626 const int *conn=_nodal_connec->getConstPointer();
6627 const int *connI=_nodal_connec_index->getConstPointer();
6628 const double *coo=_coords->getConstPointer();
6630 for(int i=0;i<nbOfCells;i++,pt++)
6632 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6635 case INTERP_KERNEL::NORM_TRI3:
6637 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
6638 *pt=INTERP_KERNEL::triAspectRatio(tmp);
6641 case INTERP_KERNEL::NORM_QUAD4:
6643 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6644 *pt=INTERP_KERNEL::quadAspectRatio(tmp);
6647 case INTERP_KERNEL::NORM_TETRA4:
6649 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6650 *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
6654 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
6656 conn+=connI[i+1]-connI[i];
6658 ret->setName("AspectRatio");
6659 ret->synchronizeTimeWithSupport();
6664 * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
6665 * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
6666 * in 3D space. Currently only cells of the following types are
6667 * treated: INTERP_KERNEL::NORM_QUAD4.
6668 * For a cell of other type an exception is thrown.
6669 * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
6671 * \f$t=\vec{da}\times\vec{ab}\f$,
6672 * \f$u=\vec{ab}\times\vec{bc}\f$
6673 * \f$v=\vec{bc}\times\vec{cd}\f$
6674 * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
6676 * W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
6678 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6679 * cells and one time, lying on \a this mesh. The caller is to delete this
6680 * field using decrRef() as it is no more needed.
6681 * \throw If the coordinates array is not set.
6682 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6683 * \throw If the connectivity data array has more than one component.
6684 * \throw If the connectivity data array has a named component.
6685 * \throw If the connectivity index data array has more than one component.
6686 * \throw If the connectivity index data array has a named component.
6687 * \throw If \a this->getMeshDimension() != 2.
6688 * \throw If \a this->getSpaceDimension() != 3.
6689 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
6691 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
6693 checkConsistencyLight();
6694 int spaceDim=getSpaceDimension();
6695 int meshDim=getMeshDimension();
6697 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
6699 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
6700 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6702 int nbOfCells=getNumberOfCells();
6703 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6704 arr->alloc(nbOfCells,1);
6705 double *pt=arr->getPointer();
6706 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6707 const int *conn=_nodal_connec->getConstPointer();
6708 const int *connI=_nodal_connec_index->getConstPointer();
6709 const double *coo=_coords->getConstPointer();
6711 for(int i=0;i<nbOfCells;i++,pt++)
6713 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6716 case INTERP_KERNEL::NORM_QUAD4:
6718 FillInCompact3DMode(3,4,conn+1,coo,tmp);
6719 *pt=INTERP_KERNEL::quadWarp(tmp);
6723 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
6725 conn+=connI[i+1]-connI[i];
6727 ret->setName("Warp");
6728 ret->synchronizeTimeWithSupport();
6734 * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
6735 * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
6736 * treated: INTERP_KERNEL::NORM_QUAD4.
6737 * The skew is computed as follow for a quad with points (a,b,c,d): let
6738 * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
6739 * then the skew is computed as:
6741 * s=\frac{u}{|u|}\cdot\frac{v}{|v|}
6744 * For a cell of other type an exception is thrown.
6745 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6746 * cells and one time, lying on \a this mesh. The caller is to delete this
6747 * field using decrRef() as it is no more needed.
6748 * \throw If the coordinates array is not set.
6749 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6750 * \throw If the connectivity data array has more than one component.
6751 * \throw If the connectivity data array has a named component.
6752 * \throw If the connectivity index data array has more than one component.
6753 * \throw If the connectivity index data array has a named component.
6754 * \throw If \a this->getMeshDimension() != 2.
6755 * \throw If \a this->getSpaceDimension() != 3.
6756 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
6758 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
6760 checkConsistencyLight();
6761 int spaceDim=getSpaceDimension();
6762 int meshDim=getMeshDimension();
6764 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
6766 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
6767 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6769 int nbOfCells=getNumberOfCells();
6770 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6771 arr->alloc(nbOfCells,1);
6772 double *pt=arr->getPointer();
6773 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6774 const int *conn=_nodal_connec->getConstPointer();
6775 const int *connI=_nodal_connec_index->getConstPointer();
6776 const double *coo=_coords->getConstPointer();
6778 for(int i=0;i<nbOfCells;i++,pt++)
6780 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6783 case INTERP_KERNEL::NORM_QUAD4:
6785 FillInCompact3DMode(3,4,conn+1,coo,tmp);
6786 *pt=INTERP_KERNEL::quadSkew(tmp);
6790 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
6792 conn+=connI[i+1]-connI[i];
6794 ret->setName("Skew");
6795 ret->synchronizeTimeWithSupport();
6800 * 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.
6802 * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
6804 * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
6806 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
6808 checkConsistencyLight();
6809 MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
6811 std::set<INTERP_KERNEL::NormalizedCellType> types;
6812 ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
6813 int spaceDim(getSpaceDimension()),nbCells(getNumberOfCells());
6814 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6815 arr->alloc(nbCells,1);
6816 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
6818 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
6819 MCAuto<DataArrayInt> cellIds(giveCellsWithType(*it));
6820 dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
6823 ret->setName("Diameter");
6828 * This method aggregate the bbox of each cell and put it into bbox parameter (xmin,xmax,ymin,ymax,zmin,zmax).
6830 * \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)
6831 * For all other cases this input parameter is ignored.
6832 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6834 * \throw If \a this is not fully set (coordinates and connectivity).
6835 * \throw If a cell in \a this has no valid nodeId.
6836 * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
6838 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
6840 int mDim(getMeshDimension()),sDim(getSpaceDimension());
6841 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.
6842 return getBoundingBoxForBBTreeFast();
6843 if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
6845 bool presenceOfQuadratic(false);
6846 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
6848 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
6849 if(cm.isQuadratic())
6850 presenceOfQuadratic=true;
6852 if(!presenceOfQuadratic)
6853 return getBoundingBoxForBBTreeFast();
6854 if(mDim==2 && sDim==2)
6855 return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
6857 return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
6859 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) !");
6863 * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
6864 * So meshes having quadratic cells the computed bounding boxes can be invalid !
6866 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6868 * \throw If \a this is not fully set (coordinates and connectivity).
6869 * \throw If a cell in \a this has no valid nodeId.
6871 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
6873 checkFullyDefined();
6874 int spaceDim(getSpaceDimension()),nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
6875 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6876 double *bbox(ret->getPointer());
6877 for(int i=0;i<nbOfCells*spaceDim;i++)
6879 bbox[2*i]=std::numeric_limits<double>::max();
6880 bbox[2*i+1]=-std::numeric_limits<double>::max();
6882 const double *coordsPtr(_coords->getConstPointer());
6883 const int *conn(_nodal_connec->getConstPointer()),*connI(_nodal_connec_index->getConstPointer());
6884 for(int i=0;i<nbOfCells;i++)
6886 int offset=connI[i]+1;
6887 int nbOfNodesForCell(connI[i+1]-offset),kk(0);
6888 for(int j=0;j<nbOfNodesForCell;j++)
6890 int nodeId=conn[offset+j];
6891 if(nodeId>=0 && nodeId<nbOfNodes)
6893 for(int k=0;k<spaceDim;k++)
6895 bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
6896 bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
6903 std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
6904 throw INTERP_KERNEL::Exception(oss.str());
6911 * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
6912 * useful for 2D meshes having quadratic cells
6913 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
6914 * the two extremities of the arc of circle).
6916 * \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)
6917 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6918 * \throw If \a this is not fully defined.
6919 * \throw If \a this is not a mesh with meshDimension equal to 2.
6920 * \throw If \a this is not a mesh with spaceDimension equal to 2.
6921 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
6923 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
6925 checkFullyDefined();
6926 int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
6927 if(spaceDim!=2 || mDim!=2)
6928 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!");
6929 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6930 double *bbox(ret->getPointer());
6931 const double *coords(_coords->getConstPointer());
6932 const int *conn(_nodal_connec->getConstPointer()),*connI(_nodal_connec_index->getConstPointer());
6933 for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
6935 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
6936 int sz(connI[1]-connI[0]-1);
6937 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=arcDetEps;
6938 std::vector<INTERP_KERNEL::Node *> nodes(sz);
6939 INTERP_KERNEL::QuadraticPolygon *pol(0);
6940 for(int j=0;j<sz;j++)
6942 int nodeId(conn[*connI+1+j]);
6943 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
6945 if(!cm.isQuadratic())
6946 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
6948 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
6949 INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
6950 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
6956 * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
6957 * useful for 2D meshes having quadratic cells
6958 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
6959 * the two extremities of the arc of circle).
6961 * \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)
6962 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6963 * \throw If \a this is not fully defined.
6964 * \throw If \a this is not a mesh with meshDimension equal to 1.
6965 * \throw If \a this is not a mesh with spaceDimension equal to 2.
6966 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
6968 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
6970 checkFullyDefined();
6971 int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
6972 if(spaceDim!=2 || mDim!=1)
6973 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!");
6974 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6975 double *bbox(ret->getPointer());
6976 const double *coords(_coords->getConstPointer());
6977 const int *conn(_nodal_connec->getConstPointer()),*connI(_nodal_connec_index->getConstPointer());
6978 for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
6980 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
6981 int sz(connI[1]-connI[0]-1);
6982 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=arcDetEps;
6983 std::vector<INTERP_KERNEL::Node *> nodes(sz);
6984 INTERP_KERNEL::Edge *edge(0);
6985 for(int j=0;j<sz;j++)
6987 int nodeId(conn[*connI+1+j]);
6988 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
6990 if(!cm.isQuadratic())
6991 edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
6993 edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
6994 const INTERP_KERNEL::Bounds& b(edge->getBounds());
6995 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
7002 namespace MEDCouplingImpl
7007 ConnReader(const int *c, int val):_conn(c),_val(val) { }
7008 bool operator() (const int& pos) { return _conn[pos]!=_val; }
7017 ConnReader2(const int *c, int val):_conn(c),_val(val) { }
7018 bool operator() (const int& pos) { return _conn[pos]==_val; }
7028 * This method expects that \a this is sorted by types. If not an exception will be thrown.
7029 * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
7030 * \a this is composed in cell types.
7031 * The returned array is of size 3*n where n is the number of different types present in \a this.
7032 * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
7033 * This parameter is kept only for compatibility with other methode listed above.
7035 std::vector<int> MEDCouplingUMesh::getDistributionOfTypes() const
7037 checkConnectivityFullyDefined();
7038 const int *conn=_nodal_connec->getConstPointer();
7039 const int *connI=_nodal_connec_index->getConstPointer();
7040 const int *work=connI;
7041 int nbOfCells=getNumberOfCells();
7042 std::size_t n=getAllGeoTypes().size();
7043 std::vector<int> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
7044 std::set<INTERP_KERNEL::NormalizedCellType> types;
7045 for(std::size_t i=0;work!=connI+nbOfCells;i++)
7047 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
7048 if(types.find(typ)!=types.end())
7050 std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
7051 oss << " is not contiguous !";
7052 throw INTERP_KERNEL::Exception(oss.str());
7056 const int *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
7057 ret[3*i+1]=(int)std::distance(work,work2);
7064 * This method is used to check that this has contiguous cell type in same order than described in \a code.
7065 * only for types cell, type node is not managed.
7066 * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
7067 * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
7068 * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
7069 * If 2 or more same geometric type is in \a code and exception is thrown too.
7071 * This method firstly checks
7072 * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
7073 * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
7074 * an exception is thrown too.
7076 * If all geometric types in \a code are exactly those in \a this null pointer is returned.
7077 * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
7078 * and a DataArrayInt instance is returned that the user has the responsability to deallocate.
7080 DataArrayInt *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<int>& code, const std::vector<const DataArrayInt *>& idsPerType) const
7083 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
7084 std::size_t sz=code.size();
7087 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
7088 std::vector<INTERP_KERNEL::NormalizedCellType> types;
7090 bool isNoPflUsed=true;
7091 for(std::size_t i=0;i<n;i++)
7092 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
7094 types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
7096 if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
7097 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
7098 isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
7101 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
7104 if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
7105 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
7106 if(types.size()==_types.size())
7109 MCAuto<DataArrayInt> ret=DataArrayInt::New();
7111 int *retPtr=ret->getPointer();
7112 const int *connI=_nodal_connec_index->getConstPointer();
7113 const int *conn=_nodal_connec->getConstPointer();
7114 int nbOfCells=getNumberOfCells();
7117 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
7119 i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,(int)(*it)));
7120 int offset=(int)std::distance(connI,i);
7121 const int *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)(*it)));
7122 int nbOfCellsOfCurType=(int)std::distance(i,j);
7123 if(code[3*kk+2]==-1)
7124 for(int k=0;k<nbOfCellsOfCurType;k++)
7128 int idInIdsPerType=code[3*kk+2];
7129 if(idInIdsPerType>=0 && idInIdsPerType<(int)idsPerType.size())
7131 const DataArrayInt *zePfl=idsPerType[idInIdsPerType];
7134 zePfl->checkAllocated();
7135 if(zePfl->getNumberOfComponents()==1)
7137 for(const int *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
7139 if(*k>=0 && *k<nbOfCellsOfCurType)
7140 *retPtr=(*k)+offset;
7143 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
7144 oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
7145 throw INTERP_KERNEL::Exception(oss.str());
7150 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
7153 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
7157 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
7158 oss << " should be in [0," << idsPerType.size() << ") !";
7159 throw INTERP_KERNEL::Exception(oss.str());
7168 * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
7169 * 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.
7170 * 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.
7171 * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
7173 * \param [in] profile
7174 * \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.
7175 * \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,
7176 * \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
7177 * \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.
7178 * This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
7179 * \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
7181 void MEDCouplingUMesh::splitProfilePerType(const DataArrayInt *profile, std::vector<int>& code, std::vector<DataArrayInt *>& idsInPflPerType, std::vector<DataArrayInt *>& idsPerType) const
7184 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
7185 if(profile->getNumberOfComponents()!=1)
7186 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
7187 checkConnectivityFullyDefined();
7188 const int *conn=_nodal_connec->getConstPointer();
7189 const int *connI=_nodal_connec_index->getConstPointer();
7190 int nbOfCells=getNumberOfCells();
7191 std::vector<INTERP_KERNEL::NormalizedCellType> types;
7192 std::vector<int> typeRangeVals(1);
7193 for(const int *i=connI;i!=connI+nbOfCells;)
7195 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7196 if(std::find(types.begin(),types.end(),curType)!=types.end())
7198 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
7200 types.push_back(curType);
7201 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7202 typeRangeVals.push_back((int)std::distance(connI,i));
7205 DataArrayInt *castArr=0,*rankInsideCast=0,*castsPresent=0;
7206 profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
7207 MCAuto<DataArrayInt> tmp0=castArr;
7208 MCAuto<DataArrayInt> tmp1=rankInsideCast;
7209 MCAuto<DataArrayInt> tmp2=castsPresent;
7211 int nbOfCastsFinal=castsPresent->getNumberOfTuples();
7212 code.resize(3*nbOfCastsFinal);
7213 std::vector< MCAuto<DataArrayInt> > idsInPflPerType2;
7214 std::vector< MCAuto<DataArrayInt> > idsPerType2;
7215 for(int i=0;i<nbOfCastsFinal;i++)
7217 int castId=castsPresent->getIJ(i,0);
7218 MCAuto<DataArrayInt> tmp3=castArr->findIdsEqual(castId);
7219 idsInPflPerType2.push_back(tmp3);
7220 code[3*i]=(int)types[castId];
7221 code[3*i+1]=tmp3->getNumberOfTuples();
7222 MCAuto<DataArrayInt> tmp4=rankInsideCast->selectByTupleId(tmp3->getConstPointer(),tmp3->getConstPointer()+tmp3->getNumberOfTuples());
7223 if(!tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
7225 tmp4->copyStringInfoFrom(*profile);
7226 idsPerType2.push_back(tmp4);
7227 code[3*i+2]=(int)idsPerType2.size()-1;
7234 std::size_t sz2=idsInPflPerType2.size();
7235 idsInPflPerType.resize(sz2);
7236 for(std::size_t i=0;i<sz2;i++)
7238 DataArrayInt *locDa=idsInPflPerType2[i];
7240 idsInPflPerType[i]=locDa;
7242 std::size_t sz=idsPerType2.size();
7243 idsPerType.resize(sz);
7244 for(std::size_t i=0;i<sz;i++)
7246 DataArrayInt *locDa=idsPerType2[i];
7248 idsPerType[i]=locDa;
7253 * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
7254 * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
7255 * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
7256 * 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.
7258 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *&revDesc, DataArrayInt *&revDescIndx, DataArrayInt *& nM1LevMeshIds, DataArrayInt *&meshnM1Old2New) const
7260 checkFullyDefined();
7261 nM1LevMesh->checkFullyDefined();
7262 if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
7263 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
7264 if(_coords!=nM1LevMesh->getCoords())
7265 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
7266 MCAuto<DataArrayInt> tmp0=DataArrayInt::New();
7267 MCAuto<DataArrayInt> tmp1=DataArrayInt::New();
7268 MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
7269 MCAuto<DataArrayInt> ret0=ret1->sortCellsInMEDFileFrmt();
7270 desc->transformWithIndArr(ret0->getConstPointer(),ret0->getConstPointer()+ret0->getNbOfElems());
7271 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
7272 tmp->setConnectivity(tmp0,tmp1);
7273 tmp->renumberCells(ret0->getConstPointer(),false);
7274 revDesc=tmp->getNodalConnectivity();
7275 revDescIndx=tmp->getNodalConnectivityIndex();
7276 DataArrayInt *ret=0;
7277 if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
7280 ret->getMaxValue(tmp2);
7282 std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
7283 throw INTERP_KERNEL::Exception(oss.str());
7288 revDescIndx->incrRef();
7291 meshnM1Old2New=ret0;
7296 * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
7297 * necessary for writing the mesh to MED file. Additionally returns a permutation array
7298 * in "Old to New" mode.
7299 * \return DataArrayInt * - a new instance of DataArrayInt. The caller is to delete
7300 * this array using decrRef() as it is no more needed.
7301 * \throw If the nodal connectivity of cells is not defined.
7303 DataArrayInt *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
7305 checkConnectivityFullyDefined();
7306 MCAuto<DataArrayInt> ret=getRenumArrForMEDFileFrmt();
7307 renumberCells(ret->getConstPointer(),false);
7312 * This methods checks that cells are sorted by their types.
7313 * This method makes asumption (no check) that connectivity is correctly set before calling.
7315 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
7317 checkFullyDefined();
7318 const int *conn=_nodal_connec->getConstPointer();
7319 const int *connI=_nodal_connec_index->getConstPointer();
7320 int nbOfCells=getNumberOfCells();
7321 std::set<INTERP_KERNEL::NormalizedCellType> types;
7322 for(const int *i=connI;i!=connI+nbOfCells;)
7324 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7325 if(types.find(curType)!=types.end())
7327 types.insert(curType);
7328 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7334 * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
7335 * The geometric type order is specified by MED file.
7337 * \sa MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
7339 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
7341 return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
7345 * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
7346 * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
7347 * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
7348 * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
7350 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
7352 checkFullyDefined();
7353 const int *conn=_nodal_connec->getConstPointer();
7354 const int *connI=_nodal_connec_index->getConstPointer();
7355 int nbOfCells=getNumberOfCells();
7359 std::set<INTERP_KERNEL::NormalizedCellType> sg;
7360 for(const int *i=connI;i!=connI+nbOfCells;)
7362 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7363 const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
7364 if(isTypeExists!=orderEnd)
7366 int pos=(int)std::distance(orderBg,isTypeExists);
7370 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7374 if(sg.find(curType)==sg.end())
7376 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7387 * This method returns 2 newly allocated DataArrayInt instances. The first is an array of size 'this->getNumberOfCells()' with one component,
7388 * 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
7389 * 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'.
7391 DataArrayInt *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayInt *&nbPerType) const
7393 checkConnectivityFullyDefined();
7394 int nbOfCells=getNumberOfCells();
7395 const int *conn=_nodal_connec->getConstPointer();
7396 const int *connI=_nodal_connec_index->getConstPointer();
7397 MCAuto<DataArrayInt> tmpa=DataArrayInt::New();
7398 MCAuto<DataArrayInt> tmpb=DataArrayInt::New();
7399 tmpa->alloc(nbOfCells,1);
7400 tmpb->alloc((int)std::distance(orderBg,orderEnd),1);
7401 tmpb->fillWithZero();
7402 int *tmp=tmpa->getPointer();
7403 int *tmp2=tmpb->getPointer();
7404 for(const int *i=connI;i!=connI+nbOfCells;i++)
7406 const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
7409 int pos=(int)std::distance(orderBg,where);
7411 tmp[std::distance(connI,i)]=pos;
7415 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
7416 std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
7417 oss << " has a type " << cm.getRepr() << " not in input array of type !";
7418 throw INTERP_KERNEL::Exception(oss.str());
7421 nbPerType=tmpb.retn();
7426 * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
7428 * \return a new object containing the old to new correspondance.
7430 * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
7432 DataArrayInt *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
7434 return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
7438 * 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.
7439 * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
7440 * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
7441 * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
7443 DataArrayInt *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
7445 DataArrayInt *nbPerType=0;
7446 MCAuto<DataArrayInt> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
7447 nbPerType->decrRef();
7448 return tmpa->buildPermArrPerLevel();
7452 * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
7453 * The number of cells remains unchanged after the call of this method.
7454 * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
7455 * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
7457 * \return the array giving the correspondance old to new.
7459 DataArrayInt *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
7461 checkFullyDefined();
7463 const int *conn=_nodal_connec->getConstPointer();
7464 const int *connI=_nodal_connec_index->getConstPointer();
7465 int nbOfCells=getNumberOfCells();
7466 std::vector<INTERP_KERNEL::NormalizedCellType> types;
7467 for(const int *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
7468 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
7470 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7471 types.push_back(curType);
7472 for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
7474 DataArrayInt *ret=DataArrayInt::New();
7475 ret->alloc(nbOfCells,1);
7476 int *retPtr=ret->getPointer();
7477 std::fill(retPtr,retPtr+nbOfCells,-1);
7479 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
7481 for(const int *i=connI;i!=connI+nbOfCells;i++)
7482 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
7483 retPtr[std::distance(connI,i)]=newCellId++;
7485 renumberCells(retPtr,false);
7490 * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
7491 * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
7492 * This method makes asumption that connectivity is correctly set before calling.
7494 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
7496 checkConnectivityFullyDefined();
7497 const int *conn=_nodal_connec->getConstPointer();
7498 const int *connI=_nodal_connec_index->getConstPointer();
7499 int nbOfCells=getNumberOfCells();
7500 std::vector<MEDCouplingUMesh *> ret;
7501 for(const int *i=connI;i!=connI+nbOfCells;)
7503 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7504 int beginCellId=(int)std::distance(connI,i);
7505 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7506 int endCellId=(int)std::distance(connI,i);
7507 int sz=endCellId-beginCellId;
7508 int *cells=new int[sz];
7509 for(int j=0;j<sz;j++)
7510 cells[j]=beginCellId+j;
7511 MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
7519 * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
7520 * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
7521 * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
7523 * \return a newly allocated instance, that the caller must manage.
7524 * \throw If \a this contains more than one geometric type.
7525 * \throw If the nodal connectivity of \a this is not fully defined.
7526 * \throw If the internal data is not coherent.
7528 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
7530 checkConnectivityFullyDefined();
7531 if(_types.size()!=1)
7532 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7533 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
7534 MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
7535 ret->setCoords(getCoords());
7536 MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
7539 MCAuto<DataArrayInt> c=convertNodalConnectivityToStaticGeoTypeMesh();
7540 retC->setNodalConnectivity(c);
7544 MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
7546 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
7547 DataArrayInt *c=0,*ci=0;
7548 convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
7549 MCAuto<DataArrayInt> cs(c),cis(ci);
7550 retD->setNodalConnectivity(cs,cis);
7555 DataArrayInt *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
7557 checkConnectivityFullyDefined();
7558 if(_types.size()!=1)
7559 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7560 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
7561 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
7564 std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
7565 oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
7566 throw INTERP_KERNEL::Exception(oss.str());
7568 int nbCells=getNumberOfCells();
7570 int nbNodesPerCell=(int)cm.getNumberOfNodes();
7571 MCAuto<DataArrayInt> connOut=DataArrayInt::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
7572 int *outPtr=connOut->getPointer();
7573 const int *conn=_nodal_connec->begin();
7574 const int *connI=_nodal_connec_index->begin();
7576 for(int i=0;i<nbCells;i++,connI++)
7578 if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
7579 outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
7582 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 << ") !";
7583 throw INTERP_KERNEL::Exception(oss.str());
7586 return connOut.retn();
7590 * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
7591 * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
7595 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayInt *&nodalConn, DataArrayInt *&nodalConnIndex) const
7597 static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
7598 checkConnectivityFullyDefined();
7599 if(_types.size()!=1)
7600 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7601 int nbCells=getNumberOfCells(),lgth=_nodal_connec->getNumberOfTuples();
7603 throw INTERP_KERNEL::Exception(msg0);
7604 MCAuto<DataArrayInt> c(DataArrayInt::New()),ci(DataArrayInt::New());
7605 c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
7606 int *cp(c->getPointer()),*cip(ci->getPointer());
7607 const int *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
7609 for(int i=0;i<nbCells;i++,cip++,incip++)
7611 int strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
7612 int delta(stop-strt);
7615 if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
7616 cp=std::copy(incp+strt,incp+stop,cp);
7618 throw INTERP_KERNEL::Exception(msg0);
7621 throw INTERP_KERNEL::Exception(msg0);
7622 cip[1]=cip[0]+delta;
7624 nodalConn=c.retn(); nodalConnIndex=ci.retn();
7628 * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
7629 * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
7630 * This method is particulary useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
7631 * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
7632 * are not used here to avoid the build of big permutation array.
7634 * \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
7635 * those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
7636 * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayInt instance whose number of tuples is equal to the number of chunks of same geotype
7637 * in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
7638 * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayInt instance having the same size than \b szOfCellGrpOfSameType. This
7639 * output array gives for each chunck of same type the corresponding mesh id in \b ms.
7640 * \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
7641 * is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
7643 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
7644 DataArrayInt *&szOfCellGrpOfSameType,
7645 DataArrayInt *&idInMsOfCellGrpOfSameType)
7647 std::vector<const MEDCouplingUMesh *> ms2;
7648 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
7651 (*it)->checkConnectivityFullyDefined();
7655 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
7656 const DataArrayDouble *refCoo=ms2[0]->getCoords();
7657 int meshDim=ms2[0]->getMeshDimension();
7658 std::vector<const MEDCouplingUMesh *> m1ssm;
7659 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
7661 std::vector<const MEDCouplingUMesh *> m1ssmSingle;
7662 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
7664 MCAuto<DataArrayInt> ret1(DataArrayInt::New()),ret2(DataArrayInt::New());
7665 ret1->alloc(0,1); ret2->alloc(0,1);
7666 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
7668 if(meshDim!=(*it)->getMeshDimension())
7669 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
7670 if(refCoo!=(*it)->getCoords())
7671 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
7672 std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
7673 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
7674 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
7675 for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
7677 MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
7678 m1ssmSingleAuto.push_back(singleCell);
7679 m1ssmSingle.push_back(singleCell);
7680 ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
7683 MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
7684 MCAuto<DataArrayInt> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
7685 std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
7686 for(std::size_t i=0;i<m1ssm.size();i++)
7687 m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
7688 MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
7689 szOfCellGrpOfSameType=ret1->renumber(renum->getConstPointer());
7690 idInMsOfCellGrpOfSameType=ret2->renumber(renum->getConstPointer());
7695 * This method returns a newly created DataArrayInt instance.
7696 * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
7698 DataArrayInt *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const int *begin, const int *end) const
7700 checkFullyDefined();
7701 const int *conn=_nodal_connec->getConstPointer();
7702 const int *connIndex=_nodal_connec_index->getConstPointer();
7703 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
7704 for(const int *w=begin;w!=end;w++)
7705 if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
7706 ret->pushBackSilent(*w);
7711 * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
7712 * are in [0:getNumberOfCells())
7714 DataArrayInt *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayInt *da) const
7716 checkFullyDefined();
7717 const int *conn=_nodal_connec->getConstPointer();
7718 const int *connI=_nodal_connec_index->getConstPointer();
7719 int nbOfCells=getNumberOfCells();
7720 std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
7721 int *tmp=new int[nbOfCells];
7722 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
7725 for(const int *i=connI;i!=connI+nbOfCells;i++)
7726 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
7727 tmp[std::distance(connI,i)]=j++;
7729 DataArrayInt *ret=DataArrayInt::New();
7730 ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
7731 ret->copyStringInfoFrom(*da);
7732 int *retPtr=ret->getPointer();
7733 const int *daPtr=da->getConstPointer();
7734 int nbOfElems=da->getNbOfElems();
7735 for(int k=0;k<nbOfElems;k++)
7736 retPtr[k]=tmp[daPtr[k]];
7742 * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
7743 * This method \b works \b for mesh sorted by type.
7744 * cells whose ids is in 'idsPerGeoType' array.
7745 * This method conserves coords and name of mesh.
7747 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const int *idsPerGeoTypeBg, const int *idsPerGeoTypeEnd) const
7749 std::vector<int> code=getDistributionOfTypes();
7750 std::size_t nOfTypesInThis=code.size()/3;
7751 int sz=0,szOfType=0;
7752 for(std::size_t i=0;i<nOfTypesInThis;i++)
7757 szOfType=code[3*i+1];
7759 for(const int *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
7760 if(*work<0 || *work>=szOfType)
7762 std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
7763 oss << ". It should be in [0," << szOfType << ") !";
7764 throw INTERP_KERNEL::Exception(oss.str());
7766 MCAuto<DataArrayInt> idsTokeep=DataArrayInt::New(); idsTokeep->alloc(sz+(int)std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
7767 int *idsPtr=idsTokeep->getPointer();
7769 for(std::size_t i=0;i<nOfTypesInThis;i++)
7772 for(int j=0;j<code[3*i+1];j++)
7775 idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind2nd(std::plus<int>(),offset));
7776 offset+=code[3*i+1];
7778 MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
7779 ret->copyTinyInfoFrom(this);
7784 * This method returns a vector of size 'this->getNumberOfCells()'.
7785 * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
7787 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
7789 int ncell=getNumberOfCells();
7790 std::vector<bool> ret(ncell);
7791 const int *cI=getNodalConnectivityIndex()->getConstPointer();
7792 const int *c=getNodalConnectivity()->getConstPointer();
7793 for(int i=0;i<ncell;i++)
7795 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
7796 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
7797 ret[i]=cm.isQuadratic();
7803 * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
7805 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
7807 if(other->getType()!=UNSTRUCTURED)
7808 throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
7809 const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
7810 return MergeUMeshes(this,otherC);
7814 * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
7815 * computed by averaging coordinates of cell nodes, so this method is not a right
7816 * choice for degnerated meshes (not well oriented, cells with measure close to zero).
7817 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
7818 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
7819 * components. The caller is to delete this array using decrRef() as it is
7821 * \throw If the coordinates array is not set.
7822 * \throw If the nodal connectivity of cells is not defined.
7823 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
7825 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
7827 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
7828 int spaceDim=getSpaceDimension();
7829 int nbOfCells=getNumberOfCells();
7830 ret->alloc(nbOfCells,spaceDim);
7831 ret->copyStringInfoFrom(*getCoords());
7832 double *ptToFill=ret->getPointer();
7833 const int *nodal=_nodal_connec->getConstPointer();
7834 const int *nodalI=_nodal_connec_index->getConstPointer();
7835 const double *coor=_coords->getConstPointer();
7836 for(int i=0;i<nbOfCells;i++)
7838 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
7839 INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
7846 * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
7847 * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
7849 * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
7850 * DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
7852 * \sa MEDCouplingUMesh::computeCellCenterOfMass
7853 * \throw If \a this is not fully defined (coordinates and connectivity)
7854 * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
7856 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
7858 checkFullyDefined();
7859 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
7860 int spaceDim=getSpaceDimension();
7861 int nbOfCells=getNumberOfCells();
7862 int nbOfNodes=getNumberOfNodes();
7863 ret->alloc(nbOfCells,spaceDim);
7864 double *ptToFill=ret->getPointer();
7865 const int *nodal=_nodal_connec->getConstPointer();
7866 const int *nodalI=_nodal_connec_index->getConstPointer();
7867 const double *coor=_coords->getConstPointer();
7868 for(int i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
7870 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
7871 std::fill(ptToFill,ptToFill+spaceDim,0.);
7872 if(type!=INTERP_KERNEL::NORM_POLYHED)
7874 for(const int *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
7876 if(*conn>=0 && *conn<nbOfNodes)
7877 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
7880 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," << nbOfNodes << ") !";
7881 throw INTERP_KERNEL::Exception(oss.str());
7884 int nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
7885 if(nbOfNodesInCell>0)
7886 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
7889 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
7890 throw INTERP_KERNEL::Exception(oss.str());
7895 std::set<int> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
7897 for(std::set<int>::const_iterator it=s.begin();it!=s.end();it++)
7899 if(*it>=0 && *it<nbOfNodes)
7900 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
7903 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," << nbOfNodes << ") !";
7904 throw INTERP_KERNEL::Exception(oss.str());
7908 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)s.size()));
7911 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
7912 throw INTERP_KERNEL::Exception(oss.str());
7920 * Returns a new DataArrayDouble holding barycenters of specified cells. The
7921 * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
7922 * are specified via an array of cell ids.
7923 * \warning Validity of the specified cell ids is not checked!
7924 * Valid range is [ 0, \a this->getNumberOfCells() ).
7925 * \param [in] begin - an array of cell ids of interest.
7926 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
7927 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
7928 * end - \a begin ) tuples per \a this->getSpaceDimension() components. The
7929 * caller is to delete this array using decrRef() as it is no more needed.
7930 * \throw If the coordinates array is not set.
7931 * \throw If the nodal connectivity of cells is not defined.
7933 * \if ENABLE_EXAMPLES
7934 * \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
7935 * \ref py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
7938 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const int *begin, const int *end) const
7940 DataArrayDouble *ret=DataArrayDouble::New();
7941 int spaceDim=getSpaceDimension();
7942 int nbOfTuple=(int)std::distance(begin,end);
7943 ret->alloc(nbOfTuple,spaceDim);
7944 double *ptToFill=ret->getPointer();
7945 double *tmp=new double[spaceDim];
7946 const int *nodal=_nodal_connec->getConstPointer();
7947 const int *nodalI=_nodal_connec_index->getConstPointer();
7948 const double *coor=_coords->getConstPointer();
7949 for(const int *w=begin;w!=end;w++)
7951 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
7952 INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
7960 * 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".
7961 * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
7962 * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
7963 * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
7964 * This method is useful to detect 2D cells in 3D space that are not coplanar.
7966 * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
7967 * \throw If spaceDim!=3 or meshDim!=2.
7968 * \throw If connectivity of \a this is invalid.
7969 * \throw If connectivity of a cell in \a this points to an invalid node.
7971 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
7973 MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
7974 int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
7975 if(getSpaceDimension()!=3 || getMeshDimension()!=2)
7976 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
7977 ret->alloc(nbOfCells,4);
7978 double *retPtr(ret->getPointer());
7979 const int *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
7980 const double *coor(_coords->begin());
7981 for(int i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
7983 double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
7984 if(nodalI[1]-nodalI[0]>=3)
7986 for(int j=0;j<3;j++)
7988 int nodeId(nodal[nodalI[0]+1+j]);
7989 if(nodeId>=0 && nodeId<nbOfNodes)
7990 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
7993 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
7994 throw INTERP_KERNEL::Exception(oss.str());
8000 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
8001 throw INTERP_KERNEL::Exception(oss.str());
8003 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
8004 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
8010 * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
8013 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
8016 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
8017 da->checkAllocated();
8018 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(da->getName(),0);
8020 int nbOfTuples=da->getNumberOfTuples();
8021 MCAuto<DataArrayInt> c=DataArrayInt::New();
8022 MCAuto<DataArrayInt> cI=DataArrayInt::New();
8023 c->alloc(2*nbOfTuples,1);
8024 cI->alloc(nbOfTuples+1,1);
8025 int *cp=c->getPointer();
8026 int *cip=cI->getPointer();
8028 for(int i=0;i<nbOfTuples;i++)
8030 *cp++=INTERP_KERNEL::NORM_POINT1;
8034 ret->setConnectivity(c,cI,true);
8038 * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
8039 * Cells and nodes of
8040 * the first mesh precede cells and nodes of the second mesh within the result mesh.
8041 * \param [in] mesh1 - the first mesh.
8042 * \param [in] mesh2 - the second mesh.
8043 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8044 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8045 * is no more needed.
8046 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
8047 * \throw If the coordinates array is not set in none of the meshes.
8048 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
8049 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
8051 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
8053 std::vector<const MEDCouplingUMesh *> tmp(2);
8054 tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
8055 return MergeUMeshes(tmp);
8059 * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
8060 * Cells and nodes of
8061 * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
8062 * \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
8063 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8064 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8065 * is no more needed.
8066 * \throw If \a a.size() == 0.
8067 * \throw If \a a[ *i* ] == NULL.
8068 * \throw If the coordinates array is not set in none of the meshes.
8069 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
8070 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
8072 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const std::vector<const MEDCouplingUMesh *>& a)
8074 std::size_t sz=a.size();
8076 return MergeUMeshesLL(a);
8077 for(std::size_t ii=0;ii<sz;ii++)
8080 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
8081 throw INTERP_KERNEL::Exception(oss.str());
8083 std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
8084 std::vector< const MEDCouplingUMesh * > aa(sz);
8086 for(std::size_t i=0;i<sz && spaceDim==-3;i++)
8088 const MEDCouplingUMesh *cur=a[i];
8089 const DataArrayDouble *coo=cur->getCoords();
8091 spaceDim=coo->getNumberOfComponents();
8094 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
8095 for(std::size_t i=0;i<sz;i++)
8097 bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
8100 return MergeUMeshesLL(aa);
8105 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesLL(const std::vector<const MEDCouplingUMesh *>& a)
8108 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : input array must be NON EMPTY !");
8109 std::vector<const MEDCouplingUMesh *>::const_iterator it=a.begin();
8110 int meshDim=(*it)->getMeshDimension();
8111 int nbOfCells=(*it)->getNumberOfCells();
8112 int meshLgth=(*it++)->getNodalConnectivityArrayLen();
8113 for(;it!=a.end();it++)
8115 if(meshDim!=(*it)->getMeshDimension())
8116 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, MergeUMeshes impossible !");
8117 nbOfCells+=(*it)->getNumberOfCells();
8118 meshLgth+=(*it)->getNodalConnectivityArrayLen();
8120 std::vector<const MEDCouplingPointSet *> aps(a.size());
8121 std::copy(a.begin(),a.end(),aps.begin());
8122 MCAuto<DataArrayDouble> pts=MergeNodesArray(aps);
8123 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("merge",meshDim);
8124 ret->setCoords(pts);
8125 MCAuto<DataArrayInt> c=DataArrayInt::New();
8126 c->alloc(meshLgth,1);
8127 int *cPtr=c->getPointer();
8128 MCAuto<DataArrayInt> cI=DataArrayInt::New();
8129 cI->alloc(nbOfCells+1,1);
8130 int *cIPtr=cI->getPointer();
8134 for(it=a.begin();it!=a.end();it++)
8136 int curNbOfCell=(*it)->getNumberOfCells();
8137 const int *curCI=(*it)->_nodal_connec_index->getConstPointer();
8138 const int *curC=(*it)->_nodal_connec->getConstPointer();
8139 cIPtr=std::transform(curCI+1,curCI+curNbOfCell+1,cIPtr,std::bind2nd(std::plus<int>(),offset));
8140 for(int j=0;j<curNbOfCell;j++)
8142 const int *src=curC+curCI[j];
8144 for(;src!=curC+curCI[j+1];src++,cPtr++)
8152 offset+=curCI[curNbOfCell];
8153 offset2+=(*it)->getNumberOfNodes();
8156 ret->setConnectivity(c,cI,true);
8163 * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
8164 * dimension and sharing the node coordinates array.
8165 * All cells of the first mesh precede all cells of the second mesh
8166 * within the result mesh.
8167 * \param [in] mesh1 - the first mesh.
8168 * \param [in] mesh2 - the second mesh.
8169 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8170 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8171 * is no more needed.
8172 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
8173 * \throw If the meshes do not share the node coordinates array.
8174 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
8175 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
8177 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
8179 std::vector<const MEDCouplingUMesh *> tmp(2);
8180 tmp[0]=mesh1; tmp[1]=mesh2;
8181 return MergeUMeshesOnSameCoords(tmp);
8185 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
8186 * dimension and sharing the node coordinates array.
8187 * All cells of the *i*-th mesh precede all cells of the
8188 * (*i*+1)-th mesh within the result mesh.
8189 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
8190 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8191 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8192 * is no more needed.
8193 * \throw If \a a.size() == 0.
8194 * \throw If \a a[ *i* ] == NULL.
8195 * \throw If the meshes do not share the node coordinates array.
8196 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
8197 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
8199 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
8202 throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
8203 for(std::size_t ii=0;ii<meshes.size();ii++)
8206 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
8207 throw INTERP_KERNEL::Exception(oss.str());
8209 const DataArrayDouble *coords=meshes.front()->getCoords();
8210 int meshDim=meshes.front()->getMeshDimension();
8211 std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
8213 int meshIndexLgth=0;
8214 for(;iter!=meshes.end();iter++)
8216 if(coords!=(*iter)->getCoords())
8217 throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
8218 if(meshDim!=(*iter)->getMeshDimension())
8219 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
8220 meshLgth+=(*iter)->getNodalConnectivityArrayLen();
8221 meshIndexLgth+=(*iter)->getNumberOfCells();
8223 MCAuto<DataArrayInt> nodal=DataArrayInt::New();
8224 nodal->alloc(meshLgth,1);
8225 int *nodalPtr=nodal->getPointer();
8226 MCAuto<DataArrayInt> nodalIndex=DataArrayInt::New();
8227 nodalIndex->alloc(meshIndexLgth+1,1);
8228 int *nodalIndexPtr=nodalIndex->getPointer();
8230 for(iter=meshes.begin();iter!=meshes.end();iter++)
8232 const int *nod=(*iter)->getNodalConnectivity()->getConstPointer();
8233 const int *index=(*iter)->getNodalConnectivityIndex()->getConstPointer();
8234 int nbOfCells=(*iter)->getNumberOfCells();
8235 int meshLgth2=(*iter)->getNodalConnectivityArrayLen();
8236 nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
8237 if(iter!=meshes.begin())
8238 nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind2nd(std::plus<int>(),offset));
8240 nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
8243 MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
8244 ret->setName("merge");
8245 ret->setMeshDimension(meshDim);
8246 ret->setConnectivity(nodal,nodalIndex,true);
8247 ret->setCoords(coords);
8252 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
8253 * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
8254 * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
8255 * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
8256 * New" mode are returned for each input mesh.
8257 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
8258 * \param [in] compType - specifies a cell comparison technique. For meaning of its
8259 * valid values [0,1,2], see zipConnectivityTraducer().
8260 * \param [in,out] corr - an array of DataArrayInt, of the same size as \a
8261 * meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
8262 * mesh. The caller is to delete each of the arrays using decrRef() as it is
8264 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8265 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8266 * is no more needed.
8267 * \throw If \a meshes.size() == 0.
8268 * \throw If \a meshes[ *i* ] == NULL.
8269 * \throw If the meshes do not share the node coordinates array.
8270 * \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
8271 * \throw If the \a meshes are of different dimension (getMeshDimension()).
8272 * \throw If the nodal connectivity of cells of any of \a meshes is not defined.
8273 * \throw If the nodal connectivity any of \a meshes includes an invalid id.
8275 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayInt *>& corr)
8277 //All checks are delegated to MergeUMeshesOnSameCoords
8278 MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
8279 MCAuto<DataArrayInt> o2n=ret->zipConnectivityTraducer(compType);
8280 corr.resize(meshes.size());
8281 std::size_t nbOfMeshes=meshes.size();
8283 const int *o2nPtr=o2n->getConstPointer();
8284 for(std::size_t i=0;i<nbOfMeshes;i++)
8286 DataArrayInt *tmp=DataArrayInt::New();
8287 int curNbOfCells=meshes[i]->getNumberOfCells();
8288 tmp->alloc(curNbOfCells,1);
8289 std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
8290 offset+=curNbOfCells;
8291 tmp->setName(meshes[i]->getName());
8298 * Makes all given meshes share the nodal connectivity array. The common connectivity
8299 * array is created by concatenating the connectivity arrays of all given meshes. All
8300 * the given meshes must be of the same space dimension but dimension of cells **can
8301 * differ**. This method is particulary useful in MEDLoader context to build a \ref
8302 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
8303 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
8304 * \param [in,out] meshes - a vector of meshes to update.
8305 * \throw If any of \a meshes is NULL.
8306 * \throw If the coordinates array is not set in any of \a meshes.
8307 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
8308 * \throw If \a meshes are of different space dimension.
8310 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
8312 std::size_t sz=meshes.size();
8315 std::vector< const DataArrayDouble * > coords(meshes.size());
8316 std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
8317 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
8321 (*it)->checkConnectivityFullyDefined();
8322 const DataArrayDouble *coo=(*it)->getCoords();
8327 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
8328 oss << " has no coordinate array defined !";
8329 throw INTERP_KERNEL::Exception(oss.str());
8334 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
8335 oss << " is null !";
8336 throw INTERP_KERNEL::Exception(oss.str());
8339 MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
8340 std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
8341 int offset=(*it)->getNumberOfNodes();
8342 (*it++)->setCoords(res);
8343 for(;it!=meshes.end();it++)
8345 int oldNumberOfNodes=(*it)->getNumberOfNodes();
8346 (*it)->setCoords(res);
8347 (*it)->shiftNodeNumbersInConn(offset);
8348 offset+=oldNumberOfNodes;
8353 * Merges nodes coincident with a given precision within all given meshes that share
8354 * the nodal connectivity array. The given meshes **can be of different** mesh
8355 * dimension. This method is particulary useful in MEDLoader context to build a \ref
8356 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
8357 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
8358 * \param [in,out] meshes - a vector of meshes to update.
8359 * \param [in] eps - the precision used to detect coincident nodes (infinite norm).
8360 * \throw If any of \a meshes is NULL.
8361 * \throw If the \a meshes do not share the same node coordinates array.
8362 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
8364 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
8368 std::set<const DataArrayDouble *> s;
8369 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
8372 s.insert((*it)->getCoords());
8375 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 !";
8376 throw INTERP_KERNEL::Exception(oss.str());
8381 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 !";
8382 throw INTERP_KERNEL::Exception(oss.str());
8384 const DataArrayDouble *coo=*(s.begin());
8388 DataArrayInt *comm,*commI;
8389 coo->findCommonTuples(eps,-1,comm,commI);
8390 MCAuto<DataArrayInt> tmp1(comm),tmp2(commI);
8391 int oldNbOfNodes=coo->getNumberOfTuples();
8393 MCAuto<DataArrayInt> o2n=DataArrayInt::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
8394 if(oldNbOfNodes==newNbOfNodes)
8396 MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->getConstPointer(),newNbOfNodes);
8397 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
8399 (*it)->renumberNodesInConn(o2n->getConstPointer());
8400 (*it)->setCoords(newCoords);
8405 * 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.
8406 * \param nbOfNodesPerLev in parameter that specifies the number of nodes of one slice of global dataset
8407 * \param isQuad specifies the policy of connectivity.
8408 * @ret in/out parameter in which the result will be append
8410 void MEDCouplingUMesh::AppendExtrudedCell(const int *connBg, const int *connEnd, int nbOfNodesPerLev, bool isQuad, std::vector<int>& ret)
8412 INTERP_KERNEL::NormalizedCellType flatType=(INTERP_KERNEL::NormalizedCellType)connBg[0];
8413 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(flatType);
8414 ret.push_back(cm.getExtrudedType());
8415 int deltaz=isQuad?2*nbOfNodesPerLev:nbOfNodesPerLev;
8418 case INTERP_KERNEL::NORM_POINT1:
8420 ret.push_back(connBg[1]);
8421 ret.push_back(connBg[1]+nbOfNodesPerLev);
8424 case INTERP_KERNEL::NORM_SEG2:
8426 int conn[4]={connBg[1],connBg[2],connBg[2]+deltaz,connBg[1]+deltaz};
8427 ret.insert(ret.end(),conn,conn+4);
8430 case INTERP_KERNEL::NORM_SEG3:
8432 int conn[8]={connBg[1],connBg[3],connBg[3]+deltaz,connBg[1]+deltaz,connBg[2],connBg[3]+nbOfNodesPerLev,connBg[2]+deltaz,connBg[1]+nbOfNodesPerLev};
8433 ret.insert(ret.end(),conn,conn+8);
8436 case INTERP_KERNEL::NORM_QUAD4:
8438 int conn[8]={connBg[1],connBg[2],connBg[3],connBg[4],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4]+deltaz};
8439 ret.insert(ret.end(),conn,conn+8);
8442 case INTERP_KERNEL::NORM_TRI3:
8444 int conn[6]={connBg[1],connBg[2],connBg[3],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz};
8445 ret.insert(ret.end(),conn,conn+6);
8448 case INTERP_KERNEL::NORM_TRI6:
8450 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,
8451 connBg[1]+nbOfNodesPerLev,connBg[2]+nbOfNodesPerLev,connBg[3]+nbOfNodesPerLev};
8452 ret.insert(ret.end(),conn,conn+15);
8455 case INTERP_KERNEL::NORM_QUAD8:
8458 connBg[1],connBg[2],connBg[3],connBg[4],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4]+deltaz,
8459 connBg[5],connBg[6],connBg[7],connBg[8],connBg[5]+deltaz,connBg[6]+deltaz,connBg[7]+deltaz,connBg[8]+deltaz,
8460 connBg[1]+nbOfNodesPerLev,connBg[2]+nbOfNodesPerLev,connBg[3]+nbOfNodesPerLev,connBg[4]+nbOfNodesPerLev
8462 ret.insert(ret.end(),conn,conn+20);
8465 case INTERP_KERNEL::NORM_POLYGON:
8467 std::back_insert_iterator< std::vector<int> > ii(ret);
8468 std::copy(connBg+1,connEnd,ii);
8470 std::reverse_iterator<const int *> rConnBg(connEnd);
8471 std::reverse_iterator<const int *> rConnEnd(connBg+1);
8472 std::transform(rConnBg,rConnEnd,ii,std::bind2nd(std::plus<int>(),deltaz));
8473 std::size_t nbOfRadFaces=std::distance(connBg+1,connEnd);
8474 for(std::size_t i=0;i<nbOfRadFaces;i++)
8477 int conn[4]={connBg[(i+1)%nbOfRadFaces+1],connBg[i+1],connBg[i+1]+deltaz,connBg[(i+1)%nbOfRadFaces+1]+deltaz};
8478 std::copy(conn,conn+4,ii);
8483 throw INTERP_KERNEL::Exception("A flat type has been detected that has not its extruded representation !");
8488 * This static operates only for coords in 3D. The polygon is specfied by its connectivity nodes in [ \a begin , \a end ).
8490 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const int *begin, const int *end, const double *coords)
8493 double v[3]={0.,0.,0.};
8494 std::size_t sz=std::distance(begin,end);
8499 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];
8500 v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
8501 v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
8503 double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
8505 // Try using quadratic points if standard points are degenerated (for example a QPOLYG with two
8506 // SEG3 forming a circle):
8507 if (fabs(ret) < INTERP_KERNEL::DEFAULT_ABS_TOL && isQuadratic)
8509 v[0] = 0.0; v[1] = 0.0; v[2] = 0.0;
8510 for(std::size_t j=0;j<sz;j++)
8512 if (j%2) // current point i is quadratic, next point i+1 is standard
8515 ip1 = (j+1)%sz; // ip1 = "i+1"
8517 else // current point i is standard, next point i+1 is quadratic
8522 v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
8523 v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
8524 v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
8526 ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
8532 * The polyhedron is specfied by its connectivity nodes in [ \a begin , \a end ).
8534 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const int *begin, const int *end, const double *coords)
8536 std::vector<std::pair<int,int> > edges;
8537 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
8538 const int *bgFace=begin;
8539 for(std::size_t i=0;i<nbOfFaces;i++)
8541 const int *endFace=std::find(bgFace+1,end,-1);
8542 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
8543 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8545 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8546 if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
8548 edges.push_back(p1);
8552 return INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)>-EPS_FOR_POLYH_ORIENTATION;
8556 * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
8558 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const int *begin, const int *end, const double *coords)
8560 double vec0[3],vec1[3];
8561 std::size_t sz=std::distance(begin,end);
8563 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
8564 int nbOfNodes=(int)sz/2;
8565 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
8566 const double *pt0=coords+3*begin[0];
8567 const double *pt1=coords+3*begin[nbOfNodes];
8568 vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
8569 return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
8572 void MEDCouplingUMesh::CorrectExtrudedStaticCell(int *begin, int *end)
8574 std::size_t sz=std::distance(begin,end);
8575 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
8576 std::size_t nbOfNodes(sz/2);
8577 std::copy(begin,end,(int *)tmp);
8578 for(std::size_t j=1;j<nbOfNodes;j++)
8580 begin[j]=tmp[nbOfNodes-j];
8581 begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
8585 bool MEDCouplingUMesh::IsTetra4WellOriented(const int *begin, const int *end, const double *coords)
8587 std::size_t sz=std::distance(begin,end);
8589 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
8590 double vec0[3],vec1[3];
8591 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
8592 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];
8593 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;
8596 bool MEDCouplingUMesh::IsPyra5WellOriented(const int *begin, const int *end, const double *coords)
8598 std::size_t sz=std::distance(begin,end);
8600 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
8602 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
8603 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
8604 return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
8608 * 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 )
8609 * 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
8612 * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
8613 * \param [in] coords the coordinates with nb of components exactly equal to 3
8614 * \param [in] begin begin of the nodal connectivity (geometric type included) of a single polyhedron cell
8615 * \param [in] end end of nodal connectivity of a single polyhedron cell (excluded)
8616 * \param [out] res the result is put at the end of the vector without any alteration of the data.
8618 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, const int *begin, const int *end, DataArrayInt *res)
8620 int nbFaces=std::count(begin+1,end,-1)+1;
8621 MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
8622 double *vPtr=v->getPointer();
8623 MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,1);
8624 double *pPtr=p->getPointer();
8625 const int *stFaceConn=begin+1;
8626 for(int i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
8628 const int *endFaceConn=std::find(stFaceConn,end,-1);
8629 ComputeVecAndPtOfFace(eps,coords->getConstPointer(),stFaceConn,endFaceConn,vPtr,pPtr);
8630 stFaceConn=endFaceConn+1;
8632 pPtr=p->getPointer(); vPtr=v->getPointer();
8633 DataArrayInt *comm1=0,*commI1=0;
8634 v->findCommonTuples(eps,-1,comm1,commI1);
8635 MCAuto<DataArrayInt> comm1Auto(comm1),commI1Auto(commI1);
8636 const int *comm1Ptr=comm1->getConstPointer();
8637 const int *commI1Ptr=commI1->getConstPointer();
8638 int nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
8639 res->pushBackSilent((int)INTERP_KERNEL::NORM_POLYHED);
8641 MCAuto<MEDCouplingUMesh> mm=MEDCouplingUMesh::New("",3);
8642 mm->setCoords(const_cast<DataArrayDouble *>(coords)); mm->allocateCells(1); mm->insertNextCell(INTERP_KERNEL::NORM_POLYHED,(int)std::distance(begin+1,end),begin+1);
8643 mm->finishInsertingCells();
8645 for(int i=0;i<nbOfGrps1;i++)
8647 int vecId=comm1Ptr[commI1Ptr[i]];
8648 MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
8649 DataArrayInt *comm2=0,*commI2=0;
8650 tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
8651 MCAuto<DataArrayInt> comm2Auto(comm2),commI2Auto(commI2);
8652 const int *comm2Ptr=comm2->getConstPointer();
8653 const int *commI2Ptr=commI2->getConstPointer();
8654 int nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
8655 for(int j=0;j<nbOfGrps2;j++)
8657 if(commI2Ptr[j+1]-commI2Ptr[j]<=1)
8659 res->insertAtTheEnd(begin,end);
8660 res->pushBackSilent(-1);
8664 int pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
8665 MCAuto<DataArrayInt> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
8666 ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
8667 DataArrayInt *tmp0=DataArrayInt::New(),*tmp1=DataArrayInt::New(),*tmp2=DataArrayInt::New(),*tmp3=DataArrayInt::New();
8668 MCAuto<MEDCouplingUMesh> mm2=mm->buildDescendingConnectivity(tmp0,tmp1,tmp2,tmp3); tmp0->decrRef(); tmp1->decrRef(); tmp2->decrRef(); tmp3->decrRef();
8669 MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(mm2->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
8670 MCAuto<DataArrayInt> idsNodeTmp=mm3->zipCoordsTraducer();
8671 MCAuto<DataArrayInt> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
8672 const int *idsNodePtr=idsNode->getConstPointer();
8673 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];
8674 double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
8675 double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
8676 if(std::abs(norm)>eps)
8678 double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
8679 mm3->rotate(center,vec,angle);
8681 mm3->changeSpaceDimension(2);
8682 MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
8683 const int *conn4=mm4->getNodalConnectivity()->getConstPointer();
8684 const int *connI4=mm4->getNodalConnectivityIndex()->getConstPointer();
8685 int nbOfCells=mm4->getNumberOfCells();
8686 for(int k=0;k<nbOfCells;k++)
8689 for(const int *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
8690 res->pushBackSilent(idsNodePtr[*work]);
8691 res->pushBackSilent(-1);
8696 res->popBackSilent();
8700 * 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
8701 * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
8703 * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
8704 * \param [in] coords coordinates expected to have 3 components.
8705 * \param [in] begin start of the nodal connectivity of the face.
8706 * \param [in] end end of the nodal connectivity (excluded) of the face.
8707 * \param [out] v the normalized vector of size 3
8708 * \param [out] p the pos of plane
8710 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const int *begin, const int *end, double *v, double *p)
8712 std::size_t nbPoints=std::distance(begin,end);
8714 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
8715 double vec[3]={0.,0.,0.};
8717 bool refFound=false;
8718 for(;j<nbPoints-1 && !refFound;j++)
8720 vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
8721 vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
8722 vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
8723 double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
8727 vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
8730 for(std::size_t i=j;i<nbPoints-1;i++)
8733 curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
8734 curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
8735 curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
8736 double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
8739 curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
8740 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];
8741 norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
8744 v[0]/=norm; v[1]/=norm; v[2]/=norm;
8745 *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
8749 throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
8753 * This method tries to obtain a well oriented polyhedron.
8754 * If the algorithm fails, an exception will be thrown.
8756 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(int *begin, int *end, const double *coords)
8758 std::list< std::pair<int,int> > edgesOK,edgesFinished;
8759 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
8760 std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
8762 int *bgFace=begin,*endFace=std::find(begin+1,end,-1);
8763 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
8764 for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<int,int> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
8766 while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
8769 std::size_t smthChanged=0;
8770 for(std::size_t i=0;i<nbOfFaces;i++)
8772 endFace=std::find(bgFace+1,end,-1);
8773 nbOfEdgesInFace=std::distance(bgFace,endFace);
8777 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8779 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8780 std::pair<int,int> p2(p1.second,p1.first);
8781 bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
8782 bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
8783 if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
8788 std::reverse(bgFace+1,endFace);
8789 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8791 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8792 std::pair<int,int> p2(p1.second,p1.first);
8793 if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
8794 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
8795 if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
8796 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
8797 std::list< std::pair<int,int> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
8798 if(it!=edgesOK.end())
8801 edgesFinished.push_back(p1);
8804 edgesOK.push_back(p1);
8811 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
8813 if(!edgesOK.empty())
8814 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
8815 if(INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)<-EPS_FOR_POLYH_ORIENTATION)
8816 {//not lucky ! The first face was not correctly oriented : reorient all faces...
8818 for(std::size_t i=0;i<nbOfFaces;i++)
8820 endFace=std::find(bgFace+1,end,-1);
8821 std::reverse(bgFace+1,endFace);
8827 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMeshLinear(const MEDCouplingUMesh *skin, const DataArrayInt *n2o) const
8829 int nbOfNodesExpected(skin->getNumberOfNodes());
8830 const int *n2oPtr(n2o->getConstPointer());
8831 MCAuto<DataArrayInt> revNodal(DataArrayInt::New()),revNodalI(DataArrayInt::New());
8832 skin->getReverseNodalConnectivity(revNodal,revNodalI);
8833 const int *revNodalPtr(revNodal->getConstPointer()),*revNodalIPtr(revNodalI->getConstPointer());
8834 const int *nodalPtr(skin->getNodalConnectivity()->getConstPointer());
8835 const int *nodalIPtr(skin->getNodalConnectivityIndex()->getConstPointer());
8836 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfNodesExpected+1,1);
8837 int *work(ret->getPointer()); *work++=INTERP_KERNEL::NORM_POLYGON;
8838 if(nbOfNodesExpected<1)
8840 int prevCell(0),prevNode(nodalPtr[nodalIPtr[0]+1]);
8841 *work++=n2oPtr[prevNode];
8842 for(int i=1;i<nbOfNodesExpected;i++)
8844 if(nodalIPtr[prevCell+1]-nodalIPtr[prevCell]==3)
8846 std::set<int> conn(nodalPtr+nodalIPtr[prevCell]+1,nodalPtr+nodalIPtr[prevCell]+3);
8847 conn.erase(prevNode);
8850 int curNode(*(conn.begin()));
8851 *work++=n2oPtr[curNode];
8852 std::set<int> shar(revNodalPtr+revNodalIPtr[curNode],revNodalPtr+revNodalIPtr[curNode+1]);
8853 shar.erase(prevCell);
8856 prevCell=*(shar.begin());
8860 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected 2 !");
8863 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected 1 !");
8866 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected cell !");
8871 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMeshQuadratic(const MEDCouplingUMesh *skin, const DataArrayInt *n2o) const
8873 int nbOfNodesExpected(skin->getNumberOfNodes());
8874 int nbOfTurn(nbOfNodesExpected/2);
8875 const int *n2oPtr(n2o->getConstPointer());
8876 MCAuto<DataArrayInt> revNodal(DataArrayInt::New()),revNodalI(DataArrayInt::New());
8877 skin->getReverseNodalConnectivity(revNodal,revNodalI);
8878 const int *revNodalPtr(revNodal->getConstPointer()),*revNodalIPtr(revNodalI->getConstPointer());
8879 const int *nodalPtr(skin->getNodalConnectivity()->getConstPointer());
8880 const int *nodalIPtr(skin->getNodalConnectivityIndex()->getConstPointer());
8881 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfNodesExpected+1,1);
8882 int *work(ret->getPointer()); *work++=INTERP_KERNEL::NORM_QPOLYG;
8883 if(nbOfNodesExpected<1)
8885 int prevCell(0),prevNode(nodalPtr[nodalIPtr[0]+1]);
8886 *work=n2oPtr[prevNode]; work[nbOfTurn]=n2oPtr[nodalPtr[nodalIPtr[0]+3]]; work++;
8887 for(int i=1;i<nbOfTurn;i++)
8889 if(nodalIPtr[prevCell+1]-nodalIPtr[prevCell]==4)
8891 std::set<int> conn(nodalPtr+nodalIPtr[prevCell]+1,nodalPtr+nodalIPtr[prevCell]+3);
8892 conn.erase(prevNode);
8895 int curNode(*(conn.begin()));
8896 *work=n2oPtr[curNode];
8897 std::set<int> shar(revNodalPtr+revNodalIPtr[curNode],revNodalPtr+revNodalIPtr[curNode+1]);
8898 shar.erase(prevCell);
8901 int curCell(*(shar.begin()));
8902 work[nbOfTurn]=n2oPtr[nodalPtr[nodalIPtr[curCell]+3]];
8908 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected 2 !");
8911 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected 1 !");
8914 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected cell !");
8920 * This method makes the assumption spacedimension == meshdimension == 2.
8921 * This method works only for linear cells.
8923 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
8925 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMesh() const
8927 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
8928 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
8929 MCAuto<MEDCouplingUMesh> skin(computeSkin());
8930 int oldNbOfNodes(skin->getNumberOfNodes());
8931 MCAuto<DataArrayInt> o2n(skin->zipCoordsTraducer());
8932 int nbOfNodesExpected(skin->getNumberOfNodes());
8933 MCAuto<DataArrayInt> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
8934 int nbCells(skin->getNumberOfCells());
8935 if(nbCells==nbOfNodesExpected)
8936 return buildUnionOf2DMeshLinear(skin,n2o);
8937 else if(2*nbCells==nbOfNodesExpected)
8938 return buildUnionOf2DMeshQuadratic(skin,n2o);
8940 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
8944 * This method makes the assumption spacedimension == meshdimension == 3.
8945 * This method works only for linear cells.
8947 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
8949 DataArrayInt *MEDCouplingUMesh::buildUnionOf3DMesh() const
8951 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8952 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
8953 MCAuto<MEDCouplingUMesh> m=computeSkin();
8954 const int *conn=m->getNodalConnectivity()->getConstPointer();
8955 const int *connI=m->getNodalConnectivityIndex()->getConstPointer();
8956 int nbOfCells=m->getNumberOfCells();
8957 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
8958 int *work=ret->getPointer(); *work++=INTERP_KERNEL::NORM_POLYHED;
8961 work=std::copy(conn+connI[0]+1,conn+connI[1],work);
8962 for(int i=1;i<nbOfCells;i++)
8965 work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
8971 * \brief Creates a graph of cell neighbors
8972 * \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
8973 * In the sky line array, graph arcs are stored in terms of (index,value) notation.
8975 * - index: 0 3 5 6 6
8976 * - value: 1 2 3 2 3 3
8977 * means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
8978 * Arcs are not doubled but reflexive (1,1) arcs are present for each cell
8980 MEDCouplingSkyLineArray *MEDCouplingUMesh::generateGraph() const
8982 checkConnectivityFullyDefined();
8984 int meshDim = this->getMeshDimension();
8985 MEDCoupling::DataArrayInt* indexr=MEDCoupling::DataArrayInt::New();
8986 MEDCoupling::DataArrayInt* revConn=MEDCoupling::DataArrayInt::New();
8987 this->getReverseNodalConnectivity(revConn,indexr);
8988 const int* indexr_ptr=indexr->getConstPointer();
8989 const int* revConn_ptr=revConn->getConstPointer();
8991 const MEDCoupling::DataArrayInt* index;
8992 const MEDCoupling::DataArrayInt* conn;
8993 conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
8994 index=this->getNodalConnectivityIndex();
8995 int nbCells=this->getNumberOfCells();
8996 const int* index_ptr=index->getConstPointer();
8997 const int* conn_ptr=conn->getConstPointer();
8999 //creating graph arcs (cell to cell relations)
9000 //arcs are stored in terms of (index,value) notation
9003 // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
9004 // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
9006 //warning here one node have less than or equal effective number of cell with it
9007 //but cell could have more than effective nodes
9008 //because other equals nodes in other domain (with other global inode)
9009 std::vector <int> cell2cell_index(nbCells+1,0);
9010 std::vector <int> cell2cell;
9011 cell2cell.reserve(3*nbCells);
9013 for (int icell=0; icell<nbCells;icell++)
9015 std::map<int,int > counter;
9016 for (int iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
9018 int inode=conn_ptr[iconn];
9019 for (int iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
9021 int icell2=revConn_ptr[iconnr];
9022 std::map<int,int>::iterator iter=counter.find(icell2);
9023 if (iter!=counter.end()) (iter->second)++;
9024 else counter.insert(std::make_pair(icell2,1));
9027 for (std::map<int,int>::const_iterator iter=counter.begin();
9028 iter!=counter.end(); iter++)
9029 if (iter->second >= meshDim)
9031 cell2cell_index[icell+1]++;
9032 cell2cell.push_back(iter->first);
9037 cell2cell_index[0]=0;
9038 for (int icell=0; icell<nbCells;icell++)
9039 cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
9041 //filling up index and value to create skylinearray structure
9042 MEDCouplingSkyLineArray* array=new MEDCouplingSkyLineArray(cell2cell_index,cell2cell);
9047 * This method put in zip format into parameter 'zipFrmt' in full interlace mode.
9048 * This format is often asked by INTERP_KERNEL algorithms to avoid many indirections into coordinates array.
9050 void MEDCouplingUMesh::FillInCompact3DMode(int spaceDim, int nbOfNodesInCell, const int *conn, const double *coo, double *zipFrmt)
9054 for(int i=0;i<nbOfNodesInCell;i++)
9055 w=std::copy(coo+3*conn[i],coo+3*conn[i]+3,w);
9056 else if(spaceDim==2)
9058 for(int i=0;i<nbOfNodesInCell;i++)
9060 w=std::copy(coo+2*conn[i],coo+2*conn[i]+2,w);
9065 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::FillInCompact3DMode : Invalid spaceDim specified : must be 2 or 3 !");
9068 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
9070 int nbOfCells=getNumberOfCells();
9072 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
9073 ofs << " <" << getVTKDataSetType() << ">\n";
9074 ofs << " <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
9075 ofs << " <PointData>\n" << pointData << std::endl;
9076 ofs << " </PointData>\n";
9077 ofs << " <CellData>\n" << cellData << std::endl;
9078 ofs << " </CellData>\n";
9079 ofs << " <Points>\n";
9080 if(getSpaceDimension()==3)
9081 _coords->writeVTK(ofs,8,"Points",byteData);
9084 MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
9085 coo->writeVTK(ofs,8,"Points",byteData);
9087 ofs << " </Points>\n";
9088 ofs << " <Cells>\n";
9089 const int *cPtr=_nodal_connec->getConstPointer();
9090 const int *cIPtr=_nodal_connec_index->getConstPointer();
9091 MCAuto<DataArrayInt> faceoffsets=DataArrayInt::New(); faceoffsets->alloc(nbOfCells,1);
9092 MCAuto<DataArrayInt> types=DataArrayInt::New(); types->alloc(nbOfCells,1);
9093 MCAuto<DataArrayInt> offsets=DataArrayInt::New(); offsets->alloc(nbOfCells,1);
9094 MCAuto<DataArrayInt> connectivity=DataArrayInt::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
9095 int *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
9096 int szFaceOffsets=0,szConn=0;
9097 for(int i=0;i<nbOfCells;i++,w1++,w2++,w3++)
9100 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
9103 *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
9104 w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
9108 int deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
9109 *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
9110 std::set<int> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
9111 *w3=szConn+(int)c.size(); szConn+=(int)c.size();
9112 w4=std::copy(c.begin(),c.end(),w4);
9115 types->transformWithIndArr(MEDCOUPLING2VTKTYPETRADUCER,MEDCOUPLING2VTKTYPETRADUCER+INTERP_KERNEL::NORM_MAXTYPE+1);
9116 types->writeVTK(ofs,8,"UInt8","types",byteData);
9117 offsets->writeVTK(ofs,8,"Int32","offsets",byteData);
9118 if(szFaceOffsets!=0)
9119 {//presence of Polyhedra
9120 connectivity->reAlloc(szConn);
9121 faceoffsets->writeVTK(ofs,8,"Int32","faceoffsets",byteData);
9122 MCAuto<DataArrayInt> faces=DataArrayInt::New(); faces->alloc(szFaceOffsets,1);
9123 w1=faces->getPointer();
9124 for(int i=0;i<nbOfCells;i++)
9125 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
9127 int nbFaces=std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1)+1;
9129 const int *w6=cPtr+cIPtr[i]+1,*w5=0;
9130 for(int j=0;j<nbFaces;j++)
9132 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
9133 *w1++=(int)std::distance(w6,w5);
9134 w1=std::copy(w6,w5,w1);
9138 faces->writeVTK(ofs,8,"Int32","faces",byteData);
9140 connectivity->writeVTK(ofs,8,"Int32","connectivity",byteData);
9141 ofs << " </Cells>\n";
9142 ofs << " </Piece>\n";
9143 ofs << " </" << getVTKDataSetType() << ">\n";
9146 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
9148 stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
9150 { stream << " Not set !"; return ; }
9151 stream << " Mesh dimension : " << _mesh_dim << ".";
9155 { stream << " No coordinates set !"; return ; }
9156 if(!_coords->isAllocated())
9157 { stream << " Coordinates set but not allocated !"; return ; }
9158 stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
9159 stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
9160 if(!_nodal_connec_index)
9161 { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
9162 if(!_nodal_connec_index->isAllocated())
9163 { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
9164 int lgth=_nodal_connec_index->getNumberOfTuples();
9165 int cpt=_nodal_connec_index->getNumberOfComponents();
9166 if(cpt!=1 || lgth<1)
9168 stream << std::endl << "Number of cells : " << lgth-1 << ".";
9171 std::string MEDCouplingUMesh::getVTKDataSetType() const
9173 return std::string("UnstructuredGrid");
9176 std::string MEDCouplingUMesh::getVTKFileExtension() const
9178 return std::string("vtu");
9182 * Partitions the first given 2D mesh using the second given 2D mesh as a tool, and
9183 * returns a result mesh constituted by polygons.
9184 * Thus the final result contains all nodes from m1 plus new nodes. However it doesn't necessarily contains
9185 * all nodes from m2.
9186 * The meshes should be in 2D space. In
9187 * addition, returns two arrays mapping cells of the result mesh to cells of the input
9189 * \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
9190 * 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)
9191 * \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
9192 * 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)
9193 * \param [in] eps - precision used to detect coincident mesh entities.
9194 * \param [out] cellNb1 - a new instance of DataArrayInt holding for each result
9195 * cell an id of the cell of \a m1 it comes from. The caller is to delete
9196 * this array using decrRef() as it is no more needed.
9197 * \param [out] cellNb2 - a new instance of DataArrayInt holding for each result
9198 * cell an id of the cell of \a m2 it comes from. -1 value means that a
9199 * result cell comes from a cell (or part of cell) of \a m1 not overlapped by
9200 * any cell of \a m2. The caller is to delete this array using decrRef() as
9201 * it is no more needed.
9202 * \return MEDCouplingUMesh * - the result 2D mesh which is a new instance of
9203 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
9204 * is no more needed.
9205 * \throw If the coordinates array is not set in any of the meshes.
9206 * \throw If the nodal connectivity of cells is not defined in any of the meshes.
9207 * \throw If any of the meshes is not a 2D mesh in 2D space.
9209 * \sa conformize2D, mergeNodes
9211 MEDCouplingUMesh *MEDCouplingUMesh::Intersect2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2,
9212 double eps, DataArrayInt *&cellNb1, DataArrayInt *&cellNb2)
9215 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshes : input meshes must be not NULL !");
9216 m1->checkFullyDefined();
9217 m2->checkFullyDefined();
9218 if(m1->getMeshDimension()!=2 || m1->getSpaceDimension()!=2 || m2->getMeshDimension()!=2 || m2->getSpaceDimension()!=2)
9219 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshes works on umeshes m1 AND m2 with meshdim equal to 2 and spaceDim equal to 2 too!");
9221 // Step 1: compute all edge intersections (new nodes)
9222 std::vector< std::vector<int> > intersectEdge1, colinear2, subDiv2;
9223 MEDCouplingUMesh *m1Desc=0,*m2Desc=0; // descending connec. meshes
9224 DataArrayInt *desc1=0,*descIndx1=0,*revDesc1=0,*revDescIndx1=0,*desc2=0,*descIndx2=0,*revDesc2=0,*revDescIndx2=0;
9225 std::vector<double> addCoo,addCoordsQuadratic; // coordinates of newly created nodes
9226 IntersectDescending2DMeshes(m1,m2,eps,intersectEdge1,colinear2, subDiv2,
9227 m1Desc,desc1,descIndx1,revDesc1,revDescIndx1,
9228 addCoo, m2Desc,desc2,descIndx2,revDesc2,revDescIndx2);
9229 revDesc1->decrRef(); revDescIndx1->decrRef(); revDesc2->decrRef(); revDescIndx2->decrRef();
9230 MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(desc2),dd4(descIndx2);
9231 MCAuto<MEDCouplingUMesh> dd5(m1Desc),dd6(m2Desc);
9233 // Step 2: re-order newly created nodes according to the ordering found in m2
9234 std::vector< std::vector<int> > intersectEdge2;
9235 BuildIntersectEdges(m1Desc,m2Desc,addCoo,subDiv2,intersectEdge2);
9236 subDiv2.clear(); dd5=0; dd6=0;
9239 std::vector<int> cr,crI; //no DataArrayInt because interface with Geometric2D
9240 std::vector<int> cNb1,cNb2; //no DataArrayInt because interface with Geometric2D
9241 BuildIntersecting2DCellsFromEdges(eps,m1,desc1->getConstPointer(),descIndx1->getConstPointer(),intersectEdge1,colinear2,m2,desc2->getConstPointer(),descIndx2->getConstPointer(),intersectEdge2,addCoo,
9242 /* outputs -> */addCoordsQuadratic,cr,crI,cNb1,cNb2);
9244 // Step 4: Prepare final result:
9245 MCAuto<DataArrayDouble> addCooDa(DataArrayDouble::New());
9246 addCooDa->alloc((int)(addCoo.size())/2,2);
9247 std::copy(addCoo.begin(),addCoo.end(),addCooDa->getPointer());
9248 MCAuto<DataArrayDouble> addCoordsQuadraticDa(DataArrayDouble::New());
9249 addCoordsQuadraticDa->alloc((int)(addCoordsQuadratic.size())/2,2);
9250 std::copy(addCoordsQuadratic.begin(),addCoordsQuadratic.end(),addCoordsQuadraticDa->getPointer());
9251 std::vector<const DataArrayDouble *> coordss(4);
9252 coordss[0]=m1->getCoords(); coordss[1]=m2->getCoords(); coordss[2]=addCooDa; coordss[3]=addCoordsQuadraticDa;
9253 MCAuto<DataArrayDouble> coo(DataArrayDouble::Aggregate(coordss));
9254 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("Intersect2D",2));
9255 MCAuto<DataArrayInt> conn(DataArrayInt::New()); conn->alloc((int)cr.size(),1); std::copy(cr.begin(),cr.end(),conn->getPointer());
9256 MCAuto<DataArrayInt> connI(DataArrayInt::New()); connI->alloc((int)crI.size(),1); std::copy(crI.begin(),crI.end(),connI->getPointer());
9257 MCAuto<DataArrayInt> c1(DataArrayInt::New()); c1->alloc((int)cNb1.size(),1); std::copy(cNb1.begin(),cNb1.end(),c1->getPointer());
9258 MCAuto<DataArrayInt> c2(DataArrayInt::New()); c2->alloc((int)cNb2.size(),1); std::copy(cNb2.begin(),cNb2.end(),c2->getPointer());
9259 ret->setConnectivity(conn,connI,true);
9260 ret->setCoords(coo);
9261 cellNb1=c1.retn(); cellNb2=c2.retn();
9267 bool IsColinearOfACellOf(const std::vector< std::vector<int> >& intersectEdge1, const std::vector<int>& candidates, int start, int stop, int& retVal)
9269 if(candidates.empty())
9271 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
9273 const std::vector<int>& pool(intersectEdge1[*it]);
9274 int tmp[2]; tmp[0]=start; tmp[1]=stop;
9275 if(std::search(pool.begin(),pool.end(),tmp,tmp+2)!=pool.end())
9280 tmp[0]=stop; tmp[1]=start;
9281 if(std::search(pool.begin(),pool.end(),tmp,tmp+2)!=pool.end())
9290 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,
9291 MCAuto<DataArrayInt>& idsInRetColinear, MCAuto<DataArrayInt>& idsInMesh1DForIdsInRetColinear)
9293 idsInRetColinear=DataArrayInt::New(); idsInRetColinear->alloc(0,1);
9294 idsInMesh1DForIdsInRetColinear=DataArrayInt::New(); idsInMesh1DForIdsInRetColinear->alloc(0,1);
9295 int nCells(mesh1D->getNumberOfCells());
9296 if(nCells!=(int)intersectEdge2.size())
9297 throw INTERP_KERNEL::Exception("BuildMesh1DCutFrom : internal error # 1 !");
9298 const DataArrayDouble *coo2(mesh1D->getCoords());
9299 const int *c(mesh1D->getNodalConnectivity()->begin()),*ci(mesh1D->getNodalConnectivityIndex()->begin());
9300 const double *coo2Ptr(coo2->begin());
9301 int offset1(coords1->getNumberOfTuples());
9302 int offset2(offset1+coo2->getNumberOfTuples());
9303 int offset3(offset2+addCoo.size()/2);
9304 std::vector<double> addCooQuad;
9305 MCAuto<DataArrayInt> cOut(DataArrayInt::New()),ciOut(DataArrayInt::New()); cOut->alloc(0,1); ciOut->alloc(1,1); ciOut->setIJ(0,0,0);
9306 int tmp[4],cicnt(0),kk(0);
9307 for(int i=0;i<nCells;i++)
9309 std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
9310 INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coo2Ptr,m));
9311 const std::vector<int>& subEdges(intersectEdge2[i]);
9312 int nbSubEdge(subEdges.size()/2);
9313 for(int j=0;j<nbSubEdge;j++,kk++)
9315 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));
9316 MCAuto<INTERP_KERNEL::Edge> e2(e->buildEdgeLyingOnMe(n1,n2));
9317 INTERP_KERNEL::Edge *e2Ptr(e2);
9318 std::map<int,int>::const_iterator itm;
9319 if(dynamic_cast<INTERP_KERNEL::EdgeArcCircle *>(e2Ptr))
9321 tmp[0]=INTERP_KERNEL::NORM_SEG3;
9322 itm=mergedNodes.find(subEdges[2*j]);
9323 tmp[1]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j];
9324 itm=mergedNodes.find(subEdges[2*j+1]);
9325 tmp[2]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j+1];
9326 tmp[3]=offset3+(int)addCooQuad.size()/2;
9328 e2->getBarycenter(tmp2); addCooQuad.insert(addCooQuad.end(),tmp2,tmp2+2);
9330 cOut->insertAtTheEnd(tmp,tmp+4);
9331 ciOut->pushBackSilent(cicnt);
9335 tmp[0]=INTERP_KERNEL::NORM_SEG2;
9336 itm=mergedNodes.find(subEdges[2*j]);
9337 tmp[1]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j];
9338 itm=mergedNodes.find(subEdges[2*j+1]);
9339 tmp[2]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j+1];
9341 cOut->insertAtTheEnd(tmp,tmp+3);
9342 ciOut->pushBackSilent(cicnt);
9345 if(IsColinearOfACellOf(intersectEdge1,colinear2[i],tmp[1],tmp[2],tmp00))
9347 idsInRetColinear->pushBackSilent(kk);
9348 idsInMesh1DForIdsInRetColinear->pushBackSilent(tmp00);
9353 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(mesh1D->getName(),1));
9354 ret->setConnectivity(cOut,ciOut,true);
9355 MCAuto<DataArrayDouble> arr3(DataArrayDouble::New());
9356 arr3->useArray(&addCoo[0],false,C_DEALLOC,(int)addCoo.size()/2,2);
9357 MCAuto<DataArrayDouble> arr4(DataArrayDouble::New()); arr4->useArray(&addCooQuad[0],false,C_DEALLOC,(int)addCooQuad.size()/2,2);
9358 std::vector<const DataArrayDouble *> coordss(4);
9359 coordss[0]=coords1; coordss[1]=mesh1D->getCoords(); coordss[2]=arr3; coordss[3]=arr4;
9360 MCAuto<DataArrayDouble> arr(DataArrayDouble::Aggregate(coordss));
9361 ret->setCoords(arr);
9365 MEDCouplingUMesh *BuildRefined2DCellLinear(const DataArrayDouble *coords, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9367 std::vector<int> allEdges;
9368 for(const int *it2(descBg);it2!=descEnd;it2++)
9370 const std::vector<int>& edge1(intersectEdge1[std::abs(*it2)-1]);
9372 allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9374 allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9376 std::size_t nb(allEdges.size());
9378 throw INTERP_KERNEL::Exception("BuildRefined2DCellLinear : internal error 1 !");
9379 std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9380 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
9381 ret->setCoords(coords);
9382 ret->allocateCells(1);
9383 std::vector<int> connOut(nbOfEdgesOf2DCellSplit);
9384 for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9385 connOut[kk]=allEdges[2*kk];
9386 ret->insertNextCell(INTERP_KERNEL::NORM_POLYGON,connOut.size(),&connOut[0]);
9390 MEDCouplingUMesh *BuildRefined2DCellQuadratic(const DataArrayDouble *coords, const MEDCouplingUMesh *mesh2D, int cellIdInMesh2D, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9392 const int *c(mesh2D->getNodalConnectivity()->begin()),*ci(mesh2D->getNodalConnectivityIndex()->begin());
9393 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[cellIdInMesh2D]]));
9395 unsigned sz(cm.getNumberOfSons2(c+ci[cellIdInMesh2D]+1,ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]-1));
9396 if(sz!=std::distance(descBg,descEnd))
9397 throw INTERP_KERNEL::Exception("BuildRefined2DCellQuadratic : internal error 1 !");
9398 INTERP_KERNEL::AutoPtr<int> tmpPtr(new int[ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]]);
9399 std::vector<int> allEdges,centers;
9400 const double *coordsPtr(coords->begin());
9401 MCAuto<DataArrayDouble> addCoo(DataArrayDouble::New()); addCoo->alloc(0,1);
9402 int offset(coords->getNumberOfTuples());
9403 for(const int *it2(descBg);it2!=descEnd;it2++,ii++)
9405 INTERP_KERNEL::NormalizedCellType typeOfSon;
9406 cm.fillSonCellNodalConnectivity2(ii,c+ci[cellIdInMesh2D]+1,ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]-1,tmpPtr,typeOfSon);
9407 const std::vector<int>& edge1(intersectEdge1[std::abs(*it2)-1]);
9409 allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9411 allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9413 centers.push_back(tmpPtr[2]);//special case where no subsplit of edge -> reuse the original center.
9415 {//the current edge has been subsplit -> create corresponding centers.
9416 std::size_t nbOfCentersToAppend(edge1.size()/2);
9417 std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9418 MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpPtr,coordsPtr,m));
9419 std::vector<int>::const_iterator it3(allEdges.end()-edge1.size());
9420 for(std::size_t k=0;k<nbOfCentersToAppend;k++)
9423 const double *aa(coordsPtr+2*(*it3++));
9424 const double *bb(coordsPtr+2*(*it3++));
9425 ee->getMiddleOfPoints(aa,bb,tmpp);
9426 addCoo->insertAtTheEnd(tmpp,tmpp+2);
9427 centers.push_back(offset+k);
9431 std::size_t nb(allEdges.size());
9433 throw INTERP_KERNEL::Exception("BuildRefined2DCellQuadratic : internal error 2 !");
9434 std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9435 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
9437 ret->setCoords(coords);
9440 addCoo->rearrange(2);
9441 addCoo=DataArrayDouble::Aggregate(coords,addCoo);
9442 ret->setCoords(addCoo);
9444 ret->allocateCells(1);
9445 std::vector<int> connOut(nbOfEdgesOf2DCellSplit);
9446 for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9447 connOut[kk]=allEdges[2*kk];
9448 connOut.insert(connOut.end(),centers.begin(),centers.end());
9449 ret->insertNextCell(INTERP_KERNEL::NORM_QPOLYG,connOut.size(),&connOut[0]);
9454 * This method creates a refinement of a cell in \a mesh2D. Those cell is defined by descending connectivity and the sorted subdivided nodal connectivity
9457 * \param [in] mesh2D - The origin 2D mesh. \b Warning \b coords are not those of \a mesh2D. But mesh2D->getCoords()==coords[:mesh2D->getNumberOfNodes()]
9459 MEDCouplingUMesh *BuildRefined2DCell(const DataArrayDouble *coords, const MEDCouplingUMesh *mesh2D, int cellIdInMesh2D, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9461 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(mesh2D->getTypeOfCell(cellIdInMesh2D)));
9462 if(!cm.isQuadratic())
9463 return BuildRefined2DCellLinear(coords,descBg,descEnd,intersectEdge1);
9465 return BuildRefined2DCellQuadratic(coords,mesh2D,cellIdInMesh2D,descBg,descEnd,intersectEdge1);
9468 void AddCellInMesh2D(MEDCouplingUMesh *mesh2D, const std::vector<int>& conn, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edges)
9471 for(std::vector< MCAuto<INTERP_KERNEL::Edge> >::const_iterator it=edges.begin();it!=edges.end();it++)
9473 const INTERP_KERNEL::Edge *ee(*it);
9474 if(dynamic_cast<const INTERP_KERNEL::EdgeArcCircle *>(ee))
9478 mesh2D->insertNextCell(INTERP_KERNEL::NORM_POLYGON,conn.size(),&conn[0]);
9481 const double *coo(mesh2D->getCoords()->begin());
9482 std::size_t sz(conn.size());
9483 std::vector<double> addCoo;
9484 std::vector<int> conn2(conn);
9485 int offset(mesh2D->getNumberOfNodes());
9486 for(std::size_t i=0;i<sz;i++)
9489 edges[(i+1)%sz]->getMiddleOfPoints(coo+2*conn[i],coo+2*conn[(i+1)%sz],tmp);// tony a chier i+1 -> i
9490 addCoo.insert(addCoo.end(),tmp,tmp+2);
9491 conn2.push_back(offset+(int)i);
9493 mesh2D->getCoords()->rearrange(1);
9494 mesh2D->getCoords()->pushBackValsSilent(&addCoo[0],&addCoo[0]+addCoo.size());
9495 mesh2D->getCoords()->rearrange(2);
9496 mesh2D->insertNextCell(INTERP_KERNEL::NORM_QPOLYG,conn2.size(),&conn2[0]);
9501 * \b WARNING edges in out1 coming from \a splitMesh1D are \b NOT oriented because only used for equation of curve.
9503 * This method cuts in 2 parts the input 2D cell given using boundaries description (\a edge1Bis and \a edge1BisPtr) using
9504 * a set of edges defined in \a splitMesh1D.
9506 void BuildMesh2DCutInternal2(const MEDCouplingUMesh *splitMesh1D, const std::vector<int>& edge1Bis, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edge1BisPtr,
9507 std::vector< std::vector<int> >& out0, std::vector< std::vector< MCAuto<INTERP_KERNEL::Edge> > >& out1)
9509 std::size_t nb(edge1Bis.size()/2);
9510 std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9511 int iEnd(splitMesh1D->getNumberOfCells());
9513 throw INTERP_KERNEL::Exception("BuildMesh2DCutInternal2 : internal error ! input 1D mesh must have at least one cell !");
9515 const int *cSplitPtr(splitMesh1D->getNodalConnectivity()->begin()),*ciSplitPtr(splitMesh1D->getNodalConnectivityIndex()->begin());
9516 for(ii=0;ii<nb && edge1Bis[2*ii]!=cSplitPtr[ciSplitPtr[0]+1];ii++);
9517 for(jj=ii;jj<nb && edge1Bis[2*jj+1]!=cSplitPtr[ciSplitPtr[iEnd-1]+2];jj++);
9520 {//the edges splitMesh1D[iStart:iEnd] does not fully cut the current 2D cell -> single output cell
9521 out0.resize(1); out1.resize(1);
9522 std::vector<int>& connOut(out0[0]);
9523 connOut.resize(nbOfEdgesOf2DCellSplit);
9524 std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr(out1[0]);
9525 edgesPtr.resize(nbOfEdgesOf2DCellSplit);
9526 for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9528 connOut[kk]=edge1Bis[2*kk];
9529 edgesPtr[kk]=edge1BisPtr[2*kk];
9534 // [i,iEnd[ contains the
9535 out0.resize(2); out1.resize(2);
9536 std::vector<int>& connOutLeft(out0[0]);
9537 std::vector<int>& connOutRight(out0[1]);//connOutLeft should end with edge1Bis[2*ii] and connOutRight should end with edge1Bis[2*jj+1]
9538 std::vector< MCAuto<INTERP_KERNEL::Edge> >& eleft(out1[0]);
9539 std::vector< MCAuto<INTERP_KERNEL::Edge> >& eright(out1[1]);
9540 for(std::size_t k=ii;k<jj+1;k++)
9541 { connOutLeft.push_back(edge1Bis[2*k+1]); eleft.push_back(edge1BisPtr[2*k+1]); }
9542 std::vector< MCAuto<INTERP_KERNEL::Edge> > ees(iEnd);
9543 for(int ik=0;ik<iEnd;ik++)
9545 std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9546 MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)cSplitPtr[ciSplitPtr[ik]],cSplitPtr+ciSplitPtr[ik]+1,splitMesh1D->getCoords()->begin(),m));
9549 for(int ik=iEnd-1;ik>=0;ik--)
9550 connOutLeft.push_back(cSplitPtr[ciSplitPtr[ik]+1]);
9551 for(std::size_t k=jj+1;k<nbOfEdgesOf2DCellSplit+ii;k++)
9552 { connOutRight.push_back(edge1Bis[2*k+1]); eright.push_back(edge1BisPtr[2*k+1]); }
9553 eleft.insert(eleft.end(),ees.rbegin(),ees.rend());
9554 for(int ik=0;ik<iEnd;ik++)
9555 connOutRight.push_back(cSplitPtr[ciSplitPtr[ik]+2]);
9556 eright.insert(eright.end(),ees.begin(),ees.end());
9568 CellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr);
9570 std::vector<int> _edges;
9571 std::vector< MCAuto<INTERP_KERNEL::Edge> > _edges_ptr;
9574 CellInfo::CellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr)
9576 std::size_t nbe(edges.size());
9577 std::vector<int> edges2(2*nbe); std::vector< MCAuto<INTERP_KERNEL::Edge> > edgesPtr2(2*nbe);
9578 for(std::size_t i=0;i<nbe;i++)
9580 edges2[2*i]=edges[i]; edges2[2*i+1]=edges[(i+1)%nbe];
9581 edgesPtr2[2*i]=edgesPtr[(i+1)%nbe]; edgesPtr2[2*i+1]=edgesPtr[(i+1)%nbe];//tony a chier
9583 _edges.resize(4*nbe); _edges_ptr.resize(4*nbe);
9584 std::copy(edges2.begin(),edges2.end(),_edges.begin()); std::copy(edges2.begin(),edges2.end(),_edges.begin()+2*nbe);
9585 std::copy(edgesPtr2.begin(),edgesPtr2.end(),_edges_ptr.begin()); std::copy(edgesPtr2.begin(),edgesPtr2.end(),_edges_ptr.begin()+2*nbe);
9591 EdgeInfo(int istart, int iend, const MCAuto<MEDCouplingUMesh>& mesh):_istart(istart),_iend(iend),_mesh(mesh),_left(-7),_right(-7) { }
9592 EdgeInfo(int istart, int iend, int pos, const MCAuto<INTERP_KERNEL::Edge>& edge):_istart(istart),_iend(iend),_edge(edge),_left(pos),_right(pos+1) { }
9593 bool isInMyRange(int pos) const { return pos>=_istart && pos<_iend; }
9594 void somethingHappendAt(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight);
9595 void feedEdgeInfoAt(double eps, const MEDCouplingUMesh *mesh2D, int offset, int neighbors[2]) const;
9599 MCAuto<MEDCouplingUMesh> _mesh;
9600 MCAuto<INTERP_KERNEL::Edge> _edge;
9605 void EdgeInfo::somethingHappendAt(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight)
9607 const MEDCouplingUMesh *mesh(_mesh);
9613 { _left++; _right++; return ; }
9616 bool isLeft(std::find(newLeft.begin(),newLeft.end(),_edge)!=newLeft.end()),isRight(std::find(newRight.begin(),newRight.end(),_edge)!=newRight.end());
9617 if((isLeft && isRight) || (!isLeft && !isRight))
9618 throw INTERP_KERNEL::Exception("EdgeInfo::somethingHappendAt : internal error # 1 !");
9629 bool isLeft(std::find(newLeft.begin(),newLeft.end(),_edge)!=newLeft.end()),isRight(std::find(newRight.begin(),newRight.end(),_edge)!=newRight.end());
9630 if((isLeft && isRight) || (!isLeft && !isRight))
9631 throw INTERP_KERNEL::Exception("EdgeInfo::somethingHappendAt : internal error # 2 !");
9646 void EdgeInfo::feedEdgeInfoAt(double eps, const MEDCouplingUMesh *mesh2D, int offset, int neighbors[2]) const
9648 const MEDCouplingUMesh *mesh(_mesh);
9651 neighbors[0]=offset+_left; neighbors[1]=offset+_right;
9654 {// not fully splitting cell case
9655 if(mesh2D->getNumberOfCells()==1)
9656 {//little optimization. 1 cell no need to find in which cell mesh is !
9657 neighbors[0]=offset; neighbors[1]=offset;
9662 MCAuto<DataArrayDouble> barys(mesh->computeCellCenterOfMass());
9663 int cellId(mesh2D->getCellContainingPoint(barys->begin(),eps));
9665 throw INTERP_KERNEL::Exception("EdgeInfo::feedEdgeInfoAt : internal error !");
9666 neighbors[0]=offset+cellId; neighbors[1]=offset+cellId;
9671 class VectorOfCellInfo
9674 VectorOfCellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr);
9675 std::size_t size() const { return _pool.size(); }
9676 int getPositionOf(double eps, const MEDCouplingUMesh *mesh) const;
9677 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);
9678 const std::vector<int>& getConnOf(int pos) const { return get(pos)._edges; }
9679 const std::vector< MCAuto<INTERP_KERNEL::Edge> >& getEdgePtrOf(int pos) const { return get(pos)._edges_ptr; }
9680 MCAuto<MEDCouplingUMesh> getZeMesh() const { return _ze_mesh; }
9681 void feedEdgeInfoAt(double eps, int pos, int offset, int neighbors[2]) const;
9683 int getZePosOfEdgeGivenItsGlobalId(int pos) const;
9684 void updateEdgeInfo(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight);
9685 const CellInfo& get(int pos) const;
9686 CellInfo& get(int pos);
9688 std::vector<CellInfo> _pool;
9689 MCAuto<MEDCouplingUMesh> _ze_mesh;
9690 std::vector<EdgeInfo> _edge_info;
9693 VectorOfCellInfo::VectorOfCellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr):_pool(1)
9695 _pool[0]._edges=edges;
9696 _pool[0]._edges_ptr=edgesPtr;
9699 int VectorOfCellInfo::getPositionOf(double eps, const MEDCouplingUMesh *mesh) const
9702 throw INTERP_KERNEL::Exception("VectorOfCellSplitter::getPositionOf : empty !");
9705 const MEDCouplingUMesh *zeMesh(_ze_mesh);
9707 throw INTERP_KERNEL::Exception("VectorOfCellSplitter::getPositionOf : null aggregated mesh !");
9708 MCAuto<DataArrayDouble> barys(mesh->computeCellCenterOfMass());
9709 return zeMesh->getCellContainingPoint(barys->begin(),eps);
9712 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)
9714 get(pos);//to check pos
9715 bool isFast(pos==0 && _pool.size()==1);
9716 std::size_t sz(edges.size());
9717 // dealing with edges
9719 _edge_info.push_back(EdgeInfo(istart,iend,mesh1DInCase));
9721 _edge_info.push_back(EdgeInfo(istart,iend,pos,edgePtrs[0].back()));
9723 std::vector<CellInfo> pool(_pool.size()-1+sz);
9724 for(int i=0;i<pos;i++)
9726 for(std::size_t j=0;j<sz;j++)
9727 pool[pos+j]=CellInfo(edges[j],edgePtrs[j]);
9728 for(int i=pos+1;i<(int)_pool.size();i++)
9729 pool[i+sz-1]=_pool[i];
9733 updateEdgeInfo(pos,edgePtrs[0],edgePtrs[1]);
9741 std::vector< MCAuto<MEDCouplingUMesh> > ms;
9744 MCAuto<MEDCouplingUMesh> elt(static_cast<MEDCouplingUMesh *>(_ze_mesh->buildPartOfMySelfSlice(0,pos,true)));
9748 if(pos<_ze_mesh->getNumberOfCells()-1)
9750 MCAuto<MEDCouplingUMesh> elt(static_cast<MEDCouplingUMesh *>(_ze_mesh->buildPartOfMySelfSlice(pos+1,_ze_mesh->getNumberOfCells(),true)));
9753 std::vector< const MEDCouplingUMesh *> ms2(ms.size());
9754 for(std::size_t j=0;j<ms2.size();j++)
9756 _ze_mesh=MEDCouplingUMesh::MergeUMeshesOnSameCoords(ms2);
9759 void VectorOfCellInfo::feedEdgeInfoAt(double eps, int pos, int offset, int neighbors[2]) const
9761 _edge_info[getZePosOfEdgeGivenItsGlobalId(pos)].feedEdgeInfoAt(eps,_ze_mesh,offset,neighbors);
9764 int VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId(int pos) const
9767 throw INTERP_KERNEL::Exception("VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId : invalid id ! Must be >=0 !");
9769 for(std::vector<EdgeInfo>::const_iterator it=_edge_info.begin();it!=_edge_info.end();it++,ret++)
9771 if((*it).isInMyRange(pos))
9774 throw INTERP_KERNEL::Exception("VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId : invalid id !");
9777 void VectorOfCellInfo::updateEdgeInfo(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight)
9779 get(pos);//to check;
9780 if(_edge_info.empty())
9782 std::size_t sz(_edge_info.size()-1);
9783 for(std::size_t i=0;i<sz;i++)
9784 _edge_info[i].somethingHappendAt(pos,newLeft,newRight);
9787 const CellInfo& VectorOfCellInfo::get(int pos) const
9789 if(pos<0 || pos>=(int)_pool.size())
9790 throw INTERP_KERNEL::Exception("VectorOfCellSplitter::get const : invalid pos !");
9794 CellInfo& VectorOfCellInfo::get(int pos)
9796 if(pos<0 || pos>=(int)_pool.size())
9797 throw INTERP_KERNEL::Exception("VectorOfCellSplitter::get : invalid pos !");
9803 * - a \b closed set of edges ( \a allEdges and \a allEdgesPtr ) that defines the split descending 2D cell.
9804 * - \a splitMesh1D a split 2D curve mesh contained into 2D cell defined above.
9806 * This method returns the 2D mesh and feeds \a idsLeftRight using offset.
9808 * Algorithm : \a splitMesh1D is cut into contiguous parts. Each contiguous parts will build incrementally the output 2D cells.
9810 * \param [in] allEdges a list of pairs (beginNode, endNode). Linked with \a allEdgesPtr to get the equation of edge.
9812 MEDCouplingUMesh *BuildMesh2DCutInternal(double eps, const MEDCouplingUMesh *splitMesh1D, const std::vector<int>& allEdges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& allEdgesPtr, int offset,
9813 MCAuto<DataArrayInt>& idsLeftRight)
9815 int nbCellsInSplitMesh1D(splitMesh1D->getNumberOfCells());
9816 if(nbCellsInSplitMesh1D==0)
9817 throw INTERP_KERNEL::Exception("BuildMesh2DCutInternal : internal error ! input 1D mesh must have at least one cell !");
9818 const int *cSplitPtr(splitMesh1D->getNodalConnectivity()->begin()),*ciSplitPtr(splitMesh1D->getNodalConnectivityIndex()->begin());
9819 std::size_t nb(allEdges.size()),jj;
9821 throw INTERP_KERNEL::Exception("BuildMesh2DCutFrom : internal error 2 !");
9822 std::vector<int> edge1Bis(nb*2);
9823 std::vector< MCAuto<INTERP_KERNEL::Edge> > edge1BisPtr(nb*2);
9824 std::copy(allEdges.begin(),allEdges.end(),edge1Bis.begin());
9825 std::copy(allEdges.begin(),allEdges.end(),edge1Bis.begin()+nb);
9826 std::copy(allEdgesPtr.begin(),allEdgesPtr.end(),edge1BisPtr.begin());
9827 std::copy(allEdgesPtr.begin(),allEdgesPtr.end(),edge1BisPtr.begin()+nb);
9829 idsLeftRight=DataArrayInt::New(); idsLeftRight->alloc(nbCellsInSplitMesh1D*2); idsLeftRight->fillWithValue(-2); idsLeftRight->rearrange(2);
9830 int *idsLeftRightPtr(idsLeftRight->getPointer());
9831 VectorOfCellInfo pool(edge1Bis,edge1BisPtr);
9832 for(int iStart=0;iStart<nbCellsInSplitMesh1D;)
9833 {// split [0:nbCellsInSplitMesh1D) in contiguous parts [iStart:iEnd)
9835 for(;iEnd<nbCellsInSplitMesh1D;)
9837 for(jj=0;jj<nb && edge1Bis[2*jj+1]!=cSplitPtr[ciSplitPtr[iEnd]+2];jj++);
9843 if(iEnd<nbCellsInSplitMesh1D)
9846 MCAuto<MEDCouplingUMesh> partOfSplitMesh1D(static_cast<MEDCouplingUMesh *>(splitMesh1D->buildPartOfMySelfSlice(iStart,iEnd,1,true)));
9847 int pos(pool.getPositionOf(eps,partOfSplitMesh1D));
9849 MCAuto<MEDCouplingUMesh>retTmp(MEDCouplingUMesh::New("",2));
9850 retTmp->setCoords(splitMesh1D->getCoords());
9851 retTmp->allocateCells();
9853 std::vector< std::vector<int> > out0;
9854 std::vector< std::vector< MCAuto<INTERP_KERNEL::Edge> > > out1;
9856 BuildMesh2DCutInternal2(partOfSplitMesh1D,pool.getConnOf(pos),pool.getEdgePtrOf(pos),out0,out1);
9857 for(std::size_t cnt=0;cnt<out0.size();cnt++)
9858 AddCellInMesh2D(retTmp,out0[cnt],out1[cnt]);
9859 pool.setMeshAt(pos,retTmp,iStart,iEnd,partOfSplitMesh1D,out0,out1);
9863 for(int mm=0;mm<nbCellsInSplitMesh1D;mm++)
9864 pool.feedEdgeInfoAt(eps,mm,offset,idsLeftRightPtr+2*mm);
9865 return pool.getZeMesh().retn();
9868 MEDCouplingUMesh *BuildMesh2DCutFrom(double eps, int cellIdInMesh2D, const MEDCouplingUMesh *mesh2DDesc, const MEDCouplingUMesh *splitMesh1D,
9869 const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1, int offset,
9870 MCAuto<DataArrayInt>& idsLeftRight)
9872 const int *cdescPtr(mesh2DDesc->getNodalConnectivity()->begin()),*cidescPtr(mesh2DDesc->getNodalConnectivityIndex()->begin());
9874 std::vector<int> allEdges;
9875 std::vector< MCAuto<INTERP_KERNEL::Edge> > allEdgesPtr; // for each sub edge in splitMesh2D the uncut Edge object of the original mesh2D
9876 for(const int *it(descBg);it!=descEnd;it++) // for all edges in the descending connectivity of the 2D mesh in relative Fortran mode
9878 int edgeId(std::abs(*it)-1);
9879 std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9880 MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)cdescPtr[cidescPtr[edgeId]],cdescPtr+cidescPtr[edgeId]+1,mesh2DDesc->getCoords()->begin(),m));
9881 const std::vector<int>& edge1(intersectEdge1[edgeId]);
9883 allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9885 allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9886 std::size_t sz(edge1.size());
9887 for(std::size_t cnt=0;cnt<sz;cnt++)
9888 allEdgesPtr.push_back(ee);
9891 return BuildMesh2DCutInternal(eps,splitMesh1D,allEdges,allEdgesPtr,offset,idsLeftRight);
9894 bool AreEdgeEqual(const double *coo2D, const INTERP_KERNEL::CellModel& typ1, const int *conn1, const INTERP_KERNEL::CellModel& typ2, const int *conn2, double eps)
9896 if(!typ1.isQuadratic() && !typ2.isQuadratic())
9897 {//easy case comparison not
9898 return conn1[0]==conn2[0] && conn1[1]==conn2[1];
9900 else if(typ1.isQuadratic() && typ2.isQuadratic())
9902 bool status0(conn1[0]==conn2[0] && conn1[1]==conn2[1]);
9905 if(conn1[2]==conn2[2])
9907 const double *a(coo2D+2*conn1[2]),*b(coo2D+2*conn2[2]);
9908 double dist(sqrt((a[0]-b[0])*(a[0]-b[0])+(a[1]-b[1])*(a[1]-b[1])));
9912 {//only one is quadratic
9913 bool status0(conn1[0]==conn2[0] && conn1[1]==conn2[1]);
9916 const double *a(0),*bb(0),*be(0);
9917 if(typ1.isQuadratic())
9919 a=coo2D+2*conn1[2]; bb=coo2D+2*conn2[0]; be=coo2D+2*conn2[1];
9923 a=coo2D+2*conn2[2]; bb=coo2D+2*conn1[0]; be=coo2D+2*conn1[1];
9925 double b[2]; b[0]=(be[0]+bb[0])/2.; b[1]=(be[1]+bb[1])/2.;
9926 double dist(sqrt((a[0]-b[0])*(a[0]-b[0])+(a[1]-b[1])*(a[1]-b[1])));
9932 * This method returns among the cellIds [ \a candidatesIn2DBg , \a candidatesIn2DEnd ) in \a mesh2DSplit those exactly sharing \a cellIdInMesh1DSplitRelative in \a mesh1DSplit.
9933 * \a mesh2DSplit and \a mesh1DSplit are expected to share the coordinates array.
9935 * \param [in] cellIdInMesh1DSplitRelative is in Fortran mode using sign to specify direction.
9937 int FindRightCandidateAmong(const MEDCouplingUMesh *mesh2DSplit, const int *candidatesIn2DBg, const int *candidatesIn2DEnd, const MEDCouplingUMesh *mesh1DSplit, int cellIdInMesh1DSplitRelative, double eps)
9939 if(candidatesIn2DEnd==candidatesIn2DBg)
9940 throw INTERP_KERNEL::Exception("FindRightCandidateAmong : internal error 1 !");
9941 const double *coo(mesh2DSplit->getCoords()->begin());
9942 if(std::distance(candidatesIn2DBg,candidatesIn2DEnd)==1)
9943 return *candidatesIn2DBg;
9944 int edgeId(std::abs(cellIdInMesh1DSplitRelative)-1);
9945 MCAuto<MEDCouplingUMesh> cur1D(static_cast<MEDCouplingUMesh *>(mesh1DSplit->buildPartOfMySelf(&edgeId,&edgeId+1,true)));
9946 if(cellIdInMesh1DSplitRelative<0)
9947 cur1D->changeOrientationOfCells();
9948 const int *c1D(cur1D->getNodalConnectivity()->begin());
9949 const INTERP_KERNEL::CellModel& ref1DType(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c1D[0]));
9950 for(const int *it=candidatesIn2DBg;it!=candidatesIn2DEnd;it++)
9952 MCAuto<MEDCouplingUMesh> cur2D(static_cast<MEDCouplingUMesh *>(mesh2DSplit->buildPartOfMySelf(it,it+1,true)));
9953 const int *c(cur2D->getNodalConnectivity()->begin()),*ci(cur2D->getNodalConnectivityIndex()->begin());
9954 const INTERP_KERNEL::CellModel &cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[0]]));
9955 unsigned sz(cm.getNumberOfSons2(c+ci[0]+1,ci[1]-ci[0]-1));
9956 INTERP_KERNEL::AutoPtr<int> tmpPtr(new int[ci[1]-ci[0]]);
9957 for(unsigned it2=0;it2<sz;it2++)
9959 INTERP_KERNEL::NormalizedCellType typeOfSon;
9960 cm.fillSonCellNodalConnectivity2(it2,c+ci[0]+1,ci[1]-ci[0]-1,tmpPtr,typeOfSon);
9961 const INTERP_KERNEL::CellModel &curCM(INTERP_KERNEL::CellModel::GetCellModel(typeOfSon));
9962 if(AreEdgeEqual(coo,ref1DType,c1D+1,curCM,tmpPtr,eps))
9966 throw INTERP_KERNEL::Exception("FindRightCandidateAmong : internal error 2 ! Unable to find the edge among split cell !");
9972 * Partitions the first given 2D mesh using the second given 1D mesh as a tool.
9973 * 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
9974 * and finaly, in case of quadratic polygon the centers of edges new nodes.
9975 * The meshes should be in 2D space. In addition, returns two arrays mapping cells of the resulting mesh to cells of the input.
9977 * \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
9978 * 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)
9979 * \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
9980 * you can invoke orderConsecutiveCells1D on \a mesh1D.
9981 * \param [in] eps - precision used to perform intersections and localization operations.
9982 * \param [out] splitMesh2D - the result of the split of \a mesh2D mesh.
9983 * \param [out] splitMesh1D - the result of the split of \a mesh1D mesh.
9984 * \param [out] cellIdInMesh2D - the array that gives for each cell id \a i in \a splitMesh2D the id in \a mesh2D it comes from.
9985 * 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.
9986 * \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
9987 * and the cell in \a splitMesh2D on the right for the 2nt component. -1 means no cell.
9988 * 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.
9990 * \sa Intersect2DMeshes, orderConsecutiveCells1D, conformize2D, mergeNodes
9992 void MEDCouplingUMesh::Intersect2DMeshWith1DLine(const MEDCouplingUMesh *mesh2D, const MEDCouplingUMesh *mesh1D, double eps, MEDCouplingUMesh *&splitMesh2D, MEDCouplingUMesh *&splitMesh1D, DataArrayInt *&cellIdInMesh2D, DataArrayInt *&cellIdInMesh1D)
9994 if(!mesh2D || !mesh1D)
9995 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshWith1DLine : input meshes must be not NULL !");
9996 mesh2D->checkFullyDefined();
9997 mesh1D->checkFullyDefined();
9998 const std::vector<std::string>& compNames(mesh2D->getCoords()->getInfoOnComponents());
9999 if(mesh2D->getMeshDimension()!=2 || mesh2D->getSpaceDimension()!=2 || mesh1D->getMeshDimension()!=1 || mesh1D->getSpaceDimension()!=2)
10000 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshWith1DLine works with mesh2D with spacedim=meshdim=2 and mesh1D with meshdim=1 spaceDim=2 !");
10001 // Step 1: compute all edge intersections (new nodes)
10002 std::vector< std::vector<int> > intersectEdge1, colinear2, subDiv2;
10003 std::vector<double> addCoo,addCoordsQuadratic; // coordinates of newly created nodes
10004 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10005 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10007 // Build desc connectivity
10008 DataArrayInt *desc1(DataArrayInt::New()),*descIndx1(DataArrayInt::New()),*revDesc1(DataArrayInt::New()),*revDescIndx1(DataArrayInt::New());
10009 MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(revDesc1),dd4(revDescIndx1);
10010 MCAuto<MEDCouplingUMesh> m1Desc(mesh2D->buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1));
10011 std::map<int,int> mergedNodes;
10012 Intersect1DMeshes(m1Desc,mesh1D,eps,intersectEdge1,colinear2,subDiv2,addCoo,mergedNodes);
10013 // use mergeNodes to fix intersectEdge1
10014 for(std::vector< std::vector<int> >::iterator it0=intersectEdge1.begin();it0!=intersectEdge1.end();it0++)
10016 std::size_t n((*it0).size()/2);
10017 int eltStart((*it0)[0]),eltEnd((*it0)[2*n-1]);
10018 std::map<int,int>::const_iterator it1;
10019 it1=mergedNodes.find(eltStart);
10020 if(it1!=mergedNodes.end())
10021 (*it0)[0]=(*it1).second;
10022 it1=mergedNodes.find(eltEnd);
10023 if(it1!=mergedNodes.end())
10024 (*it0)[2*n-1]=(*it1).second;
10027 MCAuto<DataArrayDouble> addCooDa(DataArrayDouble::New());
10028 addCooDa->useArray(&addCoo[0],false,C_DEALLOC,(int)addCoo.size()/2,2);
10029 // Step 2: re-order newly created nodes according to the ordering found in m2
10030 std::vector< std::vector<int> > intersectEdge2;
10031 BuildIntersectEdges(m1Desc,mesh1D,addCoo,subDiv2,intersectEdge2);
10033 // Step 3: compute splitMesh1D
10034 MCAuto<DataArrayInt> idsInRet1Colinear,idsInDescMesh2DForIdsInRetColinear;
10035 MCAuto<DataArrayInt> ret2(DataArrayInt::New()); ret2->alloc(0,1);
10036 MCAuto<MEDCouplingUMesh> ret1(BuildMesh1DCutFrom(mesh1D,intersectEdge2,mesh2D->getCoords(),addCoo,mergedNodes,colinear2,intersectEdge1,
10037 idsInRet1Colinear,idsInDescMesh2DForIdsInRetColinear));
10038 MCAuto<DataArrayInt> ret3(DataArrayInt::New()); ret3->alloc(ret1->getNumberOfCells()*2,1); ret3->fillWithValue(std::numeric_limits<int>::max()); ret3->rearrange(2);
10039 MCAuto<DataArrayInt> idsInRet1NotColinear(idsInRet1Colinear->buildComplement(ret1->getNumberOfCells()));
10040 // deal with cells in mesh2D that are not cut but only some of their edges are
10041 MCAuto<DataArrayInt> idsInDesc2DToBeRefined(idsInDescMesh2DForIdsInRetColinear->deepCopy());
10042 idsInDesc2DToBeRefined->abs(); idsInDesc2DToBeRefined->applyLin(1,-1);
10043 idsInDesc2DToBeRefined=idsInDesc2DToBeRefined->buildUnique();
10044 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
10045 if(!idsInDesc2DToBeRefined->empty())
10047 DataArrayInt *out0(0),*outi0(0);
10048 MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
10049 MCAuto<DataArrayInt> outi0s(outi0);
10051 out0s=out0s->buildUnique();
10055 MCAuto<MEDCouplingUMesh> ret1NonCol(static_cast<MEDCouplingUMesh *>(ret1->buildPartOfMySelf(idsInRet1NotColinear->begin(),idsInRet1NotColinear->end())));
10056 MCAuto<DataArrayDouble> baryRet1(ret1NonCol->computeCellCenterOfMass());
10057 MCAuto<DataArrayInt> elts,eltsIndex;
10058 mesh2D->getCellsContainingPoints(baryRet1->begin(),baryRet1->getNumberOfTuples(),eps,elts,eltsIndex);
10059 MCAuto<DataArrayInt> eltsIndex2(eltsIndex->deltaShiftIndex());
10060 MCAuto<DataArrayInt> eltsIndex3(eltsIndex2->findIdsEqual(1));
10061 if(eltsIndex2->count(0)+eltsIndex3->getNumberOfTuples()!=ret1NonCol->getNumberOfCells())
10062 throw INTERP_KERNEL::Exception("Intersect2DMeshWith1DLine : internal error 1 !");
10063 MCAuto<DataArrayInt> cellsToBeModified(elts->buildUnique());
10064 MCAuto<DataArrayInt> untouchedCells(cellsToBeModified->buildComplement(mesh2D->getNumberOfCells()));
10065 if((DataArrayInt *)out0s)
10066 untouchedCells=untouchedCells->buildSubstraction(out0s);//if some edges in ret1 are colinear to descending mesh of mesh2D remove cells from untouched one
10067 std::vector< MCAuto<MEDCouplingUMesh> > outMesh2DSplit;
10068 // OK all is ready to insert in ret2 mesh
10069 if(!untouchedCells->empty())
10070 {// the most easy part, cells in mesh2D not impacted at all
10071 outMesh2DSplit.push_back(static_cast<MEDCouplingUMesh *>(mesh2D->buildPartOfMySelf(untouchedCells->begin(),untouchedCells->end())));
10072 outMesh2DSplit.back()->setCoords(ret1->getCoords());
10073 ret2->pushBackValsSilent(untouchedCells->begin(),untouchedCells->end());
10075 if((DataArrayInt *)out0s)
10076 {// here dealing with cells in out0s but not in cellsToBeModified
10077 MCAuto<DataArrayInt> fewModifiedCells(out0s->buildSubstraction(cellsToBeModified));
10078 const int *rdptr(dd3->begin()),*rdiptr(dd4->begin()),*dptr(dd1->begin()),*diptr(dd2->begin());
10079 for(const int *it=fewModifiedCells->begin();it!=fewModifiedCells->end();it++)
10081 outMesh2DSplit.push_back(BuildRefined2DCell(ret1->getCoords(),mesh2D,*it,dptr+diptr[*it],dptr+diptr[*it+1],intersectEdge1));
10082 ret1->setCoords(outMesh2DSplit.back()->getCoords());
10084 int offset(ret2->getNumberOfTuples());
10085 ret2->pushBackValsSilent(fewModifiedCells->begin(),fewModifiedCells->end());
10086 MCAuto<DataArrayInt> partOfRet3(DataArrayInt::New()); partOfRet3->alloc(2*idsInRet1Colinear->getNumberOfTuples(),1);
10087 partOfRet3->fillWithValue(std::numeric_limits<int>::max()); partOfRet3->rearrange(2);
10088 int kk(0),*ret3ptr(partOfRet3->getPointer());
10089 for(const int *it=idsInDescMesh2DForIdsInRetColinear->begin();it!=idsInDescMesh2DForIdsInRetColinear->end();it++,kk++)
10091 int faceId(std::abs(*it)-1);
10092 for(const int *it2=rdptr+rdiptr[faceId];it2!=rdptr+rdiptr[faceId+1];it2++)
10094 int tmp(fewModifiedCells->findIdFirstEqual(*it2));
10097 if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],-(*it))!=dptr+diptr[*it2+1])
10098 ret3ptr[2*kk]=tmp+offset;
10099 if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],(*it))!=dptr+diptr[*it2+1])
10100 ret3ptr[2*kk+1]=tmp+offset;
10103 {//the current edge is shared by a 2D cell that will be split just after
10104 if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],-(*it))!=dptr+diptr[*it2+1])
10105 ret3ptr[2*kk]=-(*it2+1);
10106 if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],(*it))!=dptr+diptr[*it2+1])
10107 ret3ptr[2*kk+1]=-(*it2+1);
10111 m1Desc->setCoords(ret1->getCoords());
10112 ret1NonCol->setCoords(ret1->getCoords());
10113 ret3->setPartOfValues3(partOfRet3,idsInRet1Colinear->begin(),idsInRet1Colinear->end(),0,2,1,true);
10114 if(!outMesh2DSplit.empty())
10116 DataArrayDouble *da(outMesh2DSplit.back()->getCoords());
10117 for(std::vector< MCAuto<MEDCouplingUMesh> >::iterator itt=outMesh2DSplit.begin();itt!=outMesh2DSplit.end();itt++)
10118 (*itt)->setCoords(da);
10121 cellsToBeModified=cellsToBeModified->buildUniqueNotSorted();
10122 for(const int *it=cellsToBeModified->begin();it!=cellsToBeModified->end();it++)
10124 MCAuto<DataArrayInt> idsNonColPerCell(elts->findIdsEqual(*it));
10125 idsNonColPerCell->transformWithIndArr(eltsIndex3->begin(),eltsIndex3->end());
10126 MCAuto<DataArrayInt> idsNonColPerCell2(idsInRet1NotColinear->selectByTupleId(idsNonColPerCell->begin(),idsNonColPerCell->end()));
10127 MCAuto<MEDCouplingUMesh> partOfMesh1CuttingCur2DCell(static_cast<MEDCouplingUMesh *>(ret1NonCol->buildPartOfMySelf(idsNonColPerCell->begin(),idsNonColPerCell->end())));
10128 MCAuto<DataArrayInt> partOfRet3;
10129 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));
10130 ret3->setPartOfValues3(partOfRet3,idsNonColPerCell2->begin(),idsNonColPerCell2->end(),0,2,1,true);
10131 outMesh2DSplit.push_back(splitOfOneCell);
10132 for(int i=0;i<splitOfOneCell->getNumberOfCells();i++)
10133 ret2->pushBackSilent(*it);
10136 std::size_t nbOfMeshes(outMesh2DSplit.size());
10137 std::vector<const MEDCouplingUMesh *> tmp(nbOfMeshes);
10138 for(std::size_t i=0;i<nbOfMeshes;i++)
10139 tmp[i]=outMesh2DSplit[i];
10141 ret1->getCoords()->setInfoOnComponents(compNames);
10142 MCAuto<MEDCouplingUMesh> ret2D(MEDCouplingUMesh::MergeUMeshesOnSameCoords(tmp));
10143 // To finish - filter ret3 - std::numeric_limits<int>::max() -> -1 - negate values must be resolved.
10144 ret3->rearrange(1);
10145 MCAuto<DataArrayInt> edgesToDealWith(ret3->findIdsStricltyNegative());
10146 for(const int *it=edgesToDealWith->begin();it!=edgesToDealWith->end();it++)
10148 int old2DCellId(-ret3->getIJ(*it,0)-1);
10149 MCAuto<DataArrayInt> candidates(ret2->findIdsEqual(old2DCellId));
10150 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
10152 ret3->changeValue(std::numeric_limits<int>::max(),-1);
10153 ret3->rearrange(2);
10155 splitMesh1D=ret1.retn();
10156 splitMesh2D=ret2D.retn();
10157 cellIdInMesh2D=ret2.retn();
10158 cellIdInMesh1D=ret3.retn();
10162 * Private. Third step of the partitioning algorithm (Intersect2DMeshes): reconstruct full 2D cells from the
10163 * (newly created) nodes corresponding to the edge intersections.
10165 * @param[out] cr, crI connectivity of the resulting mesh
10166 * @param[out] cNb1, cNb2 correspondance arrays giving for the merged mesh the initial cells IDs in m1 / m2
10167 * TODO: describe input parameters
10169 void MEDCouplingUMesh::BuildIntersecting2DCellsFromEdges(double eps, const MEDCouplingUMesh *m1, const int *desc1, const int *descIndx1,
10170 const std::vector<std::vector<int> >& intesctEdges1, const std::vector< std::vector<int> >& colinear2,
10171 const MEDCouplingUMesh *m2, const int *desc2, const int *descIndx2, const std::vector<std::vector<int> >& intesctEdges2,
10172 const std::vector<double>& addCoords,
10173 std::vector<double>& addCoordsQuadratic, std::vector<int>& cr, std::vector<int>& crI, std::vector<int>& cNb1, std::vector<int>& cNb2)
10175 static const int SPACEDIM=2;
10176 const double *coo1(m1->getCoords()->getConstPointer());
10177 const int *conn1(m1->getNodalConnectivity()->getConstPointer()),*connI1(m1->getNodalConnectivityIndex()->getConstPointer());
10178 int offset1(m1->getNumberOfNodes());
10179 const double *coo2(m2->getCoords()->getConstPointer());
10180 const int *conn2(m2->getNodalConnectivity()->getConstPointer()),*connI2(m2->getNodalConnectivityIndex()->getConstPointer());
10181 int offset2(offset1+m2->getNumberOfNodes());
10182 int offset3(offset2+((int)addCoords.size())/2);
10183 MCAuto<DataArrayDouble> bbox1Arr(m1->getBoundingBoxForBBTree()),bbox2Arr(m2->getBoundingBoxForBBTree());
10184 const double *bbox1(bbox1Arr->begin()),*bbox2(bbox2Arr->begin());
10185 // Here a BBTree on 2D-cells, not on segments:
10186 BBTree<SPACEDIM,int> myTree(bbox2,0,0,m2->getNumberOfCells(),eps);
10187 int ncell1(m1->getNumberOfCells());
10189 for(int i=0;i<ncell1;i++)
10191 std::vector<int> candidates2;
10192 myTree.getIntersectingElems(bbox1+i*2*SPACEDIM,candidates2);
10193 std::map<INTERP_KERNEL::Node *,int> mapp;
10194 std::map<int,INTERP_KERNEL::Node *> mappRev;
10195 INTERP_KERNEL::QuadraticPolygon pol1;
10196 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn1[connI1[i]];
10197 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
10198 // Populate mapp and mappRev with nodes from the current cell (i) from mesh1 - this also builds the Node* objects:
10199 MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,/* output */mapp,mappRev);
10200 // pol1 is the full cell from mesh2, in QP format, with all the additional intersecting nodes.
10201 pol1.buildFromCrudeDataArray(mappRev,cm.isQuadratic(),conn1+connI1[i]+1,coo1,
10202 desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1);
10204 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
10205 std::set<INTERP_KERNEL::Edge *> edgesBoundary2;// store all edges that are on boundary of (pol2 intersect pol1) minus edges on pol1.
10206 INTERP_KERNEL::IteratorOnComposedEdge it1(&pol1);
10207 for(it1.first();!it1.finished();it1.next())
10208 edges1.insert(it1.current()->getPtr());
10210 std::map<int,std::vector<INTERP_KERNEL::ElementaryEdge *> > edgesIn2ForShare; // common edges
10211 std::vector<INTERP_KERNEL::QuadraticPolygon> pol2s(candidates2.size());
10213 for(std::vector<int>::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++,ii++)
10215 INTERP_KERNEL::NormalizedCellType typ2=(INTERP_KERNEL::NormalizedCellType)conn2[connI2[*it2]];
10216 const INTERP_KERNEL::CellModel& cm2=INTERP_KERNEL::CellModel::GetCellModel(typ2);
10217 // Complete mapping with elements coming from the current cell it2 in mesh2:
10218 MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,/* output */mapp,mappRev);
10219 // pol2 is the new QP in the final merged result.
10220 pol2s[ii].buildFromCrudeDataArray2(mappRev,cm2.isQuadratic(),conn2+connI2[*it2]+1,coo2,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,
10221 pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2, /* output */ edgesIn2ForShare);
10224 for(std::vector<int>::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++,ii++)
10226 INTERP_KERNEL::ComposedEdge::InitLocationsWithOther(pol1,pol2s[ii]);
10227 pol2s[ii].updateLocOfEdgeFromCrudeDataArray2(desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2);
10228 //MEDCouplingUMeshAssignOnLoc(pol1,pol2,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,colinear2);
10229 pol1.buildPartitionsAbs(pol2s[ii],edges1,edgesBoundary2,mapp,i,*it2,offset3,addCoordsQuadratic,cr,crI,cNb1,cNb2);
10231 // Deals with remaining (non-consumed) edges from m1: these are the edges that were never touched
10232 // by m2 but that we still want to keep in the final result.
10233 if(!edges1.empty())
10237 INTERP_KERNEL::QuadraticPolygon::ComputeResidual(pol1,edges1,edgesBoundary2,mapp,offset3,i,addCoordsQuadratic,cr,crI,cNb1,cNb2);
10239 catch(INTERP_KERNEL::Exception& e)
10241 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();
10242 throw INTERP_KERNEL::Exception(oss.str());
10245 for(std::map<int,INTERP_KERNEL::Node *>::const_iterator it=mappRev.begin();it!=mappRev.end();it++)
10246 (*it).second->decrRef();
10251 * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
10252 * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
10253 * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
10254 * The caller is to deal with the resulting DataArrayInt.
10255 * \throw If the coordinate array is not set.
10256 * \throw If the nodal connectivity of the cells is not defined.
10257 * \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
10258 * \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
10260 * \sa DataArrayInt::sortEachPairToMakeALinkedList
10262 DataArrayInt *MEDCouplingUMesh::orderConsecutiveCells1D() const
10264 checkFullyDefined();
10265 if(getMeshDimension()!=1)
10266 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
10268 // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
10269 MCAuto<DataArrayInt> _d(DataArrayInt::New()),_dI(DataArrayInt::New());
10270 MCAuto<DataArrayInt> _rD(DataArrayInt::New()),_rDI(DataArrayInt::New());
10271 MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
10272 const int *d(_d->getConstPointer()), *dI(_dI->getConstPointer());
10273 const int *rD(_rD->getConstPointer()), *rDI(_rDI->getConstPointer());
10274 MCAuto<DataArrayInt> _dsi(_rDI->deltaShiftIndex());
10275 const int * dsi(_dsi->getConstPointer());
10276 MCAuto<DataArrayInt> dsii = _dsi->findIdsNotInRange(0,3);
10278 if (dsii->getNumberOfTuples())
10279 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
10281 int nc(getNumberOfCells());
10282 MCAuto<DataArrayInt> result(DataArrayInt::New());
10283 result->alloc(nc,1);
10285 // set of edges not used so far
10286 std::set<int> edgeSet;
10287 for (int i=0; i<nc; edgeSet.insert(i), i++);
10291 // while we have points with only one neighbor segments
10294 std::list<int> linePiece;
10295 // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
10296 for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
10298 // Fill the list forward (resp. backward) from the start segment:
10299 int activeSeg = startSeg;
10300 int prevPointId = -20;
10302 while (!edgeSet.empty())
10304 if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
10307 linePiece.push_back(activeSeg);
10309 linePiece.push_front(activeSeg);
10310 edgeSet.erase(activeSeg);
10313 int ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
10314 ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
10315 if (dsi[ptId] == 1) // hitting the end of the line
10317 prevPointId = ptId;
10318 int seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
10319 activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
10322 // Done, save final piece into DA:
10323 std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
10324 newIdx += linePiece.size();
10326 // identify next valid start segment (one which is not consumed)
10327 if(!edgeSet.empty())
10328 startSeg = *(edgeSet.begin());
10330 while (!edgeSet.empty());
10331 return result.retn();
10336 void IKGeo2DInternalMapper2(INTERP_KERNEL::Node *n, const std::map<MCAuto<INTERP_KERNEL::Node>,int>& m, int forbVal0, int forbVal1, std::vector<int>& isect)
10338 MCAuto<INTERP_KERNEL::Node> nTmp(n); nTmp->incrRef();
10339 std::map<MCAuto<INTERP_KERNEL::Node>,int>::const_iterator it(m.find(nTmp));
10341 throw INTERP_KERNEL::Exception("Internal error in remapping !");
10342 int v((*it).second);
10343 if(v==forbVal0 || v==forbVal1)
10345 if(std::find(isect.begin(),isect.end(),v)==isect.end())
10346 isect.push_back(v);
10349 bool IKGeo2DInternalMapper(const INTERP_KERNEL::ComposedEdge& c, const std::map<MCAuto<INTERP_KERNEL::Node>,int>& m, int forbVal0, int forbVal1, std::vector<int>& isect)
10354 bool presenceOfOn(false);
10355 for(int i=0;i<sz;i++)
10357 INTERP_KERNEL::ElementaryEdge *e(c[i]);
10358 if(e->getLoc()!=INTERP_KERNEL::FULL_ON_1)
10360 IKGeo2DInternalMapper2(e->getStartNode(),m,forbVal0,forbVal1,isect);
10361 IKGeo2DInternalMapper2(e->getEndNode(),m,forbVal0,forbVal1,isect);
10363 return presenceOfOn;
10369 * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
10370 * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
10371 * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
10372 * a minimal creation of new nodes is wanted.
10373 * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
10374 * nodes if a SEG3 is split without information of middle.
10375 * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
10376 * avoid to have a non conform mesh.
10378 * \return int - the number of new nodes created (in most of cases 0).
10380 * \throw If \a this is not coherent.
10381 * \throw If \a this has not spaceDim equal to 2.
10382 * \throw If \a this has not meshDim equal to 2.
10383 * \throw If some subcells needed to be split are orphan.
10384 * \sa MEDCouplingUMesh::conformize2D
10386 int MEDCouplingUMesh::split2DCells(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *midOpt, const DataArrayInt *midOptI)
10388 if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
10389 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
10390 desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
10391 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10392 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10393 if(midOpt==0 && midOptI==0)
10395 split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
10398 else if(midOpt!=0 && midOptI!=0)
10399 return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
10401 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
10405 * \b WARNING this method is \b potentially \b non \b const (if returned array is empty).
10406 * \b WARNING this method lead to have a non geometric type sorted mesh (for MED file users) !
10407 * 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
10408 * 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).
10409 * 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.
10411 * Whatever the returned value, this method does not alter the order of cells in \a this neither the orientation of cells.
10412 * The modified cells, if any, are systematically declared as NORM_POLYGON or NORM_QPOLYG depending on the initial quadraticness of geometric type.
10414 * This method expects that \b this has a meshDim equal 2 and spaceDim equal to 2 too.
10415 * This method expects that all nodes in \a this are not closer than \a eps.
10416 * If it is not the case you can invoke MEDCouplingUMesh::mergeNodes before calling this method.
10418 * \param [in] eps the relative error to detect merged edges.
10419 * \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
10420 * that the user is expected to deal with.
10422 * \throw If \a this is not coherent.
10423 * \throw If \a this has not spaceDim equal to 2.
10424 * \throw If \a this has not meshDim equal to 2.
10425 * \sa MEDCouplingUMesh::mergeNodes, MEDCouplingUMesh::split2DCells
10427 DataArrayInt *MEDCouplingUMesh::conformize2D(double eps)
10429 static const int SPACEDIM=2;
10430 checkConsistencyLight();
10431 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10432 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::conformize2D : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10433 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
10434 MCAuto<MEDCouplingUMesh> mDesc(buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));
10435 const int *c(mDesc->getNodalConnectivity()->getConstPointer()),*ci(mDesc->getNodalConnectivityIndex()->getConstPointer()),*rd(revDesc1->getConstPointer()),*rdi(revDescIndx1->getConstPointer());
10436 MCAuto<DataArrayDouble> bboxArr(mDesc->getBoundingBoxForBBTree());
10437 const double *bbox(bboxArr->begin()),*coords(getCoords()->begin());
10438 int nCell(getNumberOfCells()),nDescCell(mDesc->getNumberOfCells());
10439 std::vector< std::vector<int> > intersectEdge(nDescCell),overlapEdge(nDescCell);
10440 std::vector<double> addCoo;
10441 BBTree<SPACEDIM,int> myTree(bbox,0,0,nDescCell,-eps);
10442 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10443 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10444 for(int i=0;i<nDescCell;i++)
10446 std::vector<int> candidates;
10447 myTree.getIntersectingElems(bbox+i*2*SPACEDIM,candidates);
10448 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
10451 std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
10452 INTERP_KERNEL::Edge *e1(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coords,m)),
10453 *e2(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[*it]],c+ci[*it]+1,coords,m));
10454 INTERP_KERNEL::MergePoints merge;
10455 INTERP_KERNEL::QuadraticPolygon c1,c2;
10456 e1->intersectWith(e2,merge,c1,c2);
10457 e1->decrRef(); e2->decrRef();
10458 if(IKGeo2DInternalMapper(c1,m,c[ci[i]+1],c[ci[i]+2],intersectEdge[i]))
10459 overlapEdge[i].push_back(*it);
10460 if(IKGeo2DInternalMapper(c2,m,c[ci[*it]+1],c[ci[*it]+2],intersectEdge[*it]))
10461 overlapEdge[*it].push_back(i);
10464 // splitting done. sort intersect point in intersectEdge.
10465 std::vector< std::vector<int> > middle(nDescCell);
10466 int nbOf2DCellsToBeSplit(0);
10467 bool middleNeedsToBeUsed(false);
10468 std::vector<bool> cells2DToTreat(nDescCell,false);
10469 for(int i=0;i<nDescCell;i++)
10471 std::vector<int>& isect(intersectEdge[i]);
10472 int sz((int)isect.size());
10475 std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
10476 INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coords,m));
10477 e->sortSubNodesAbs(coords,isect);
10482 int idx0(rdi[i]),idx1(rdi[i+1]);
10484 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::conformize2D : internal error #0 !");
10485 if(!cells2DToTreat[rd[idx0]])
10487 cells2DToTreat[rd[idx0]]=true;
10488 nbOf2DCellsToBeSplit++;
10490 // try to reuse at most eventual 'middle' of SEG3
10491 std::vector<int>& mid(middle[i]);
10492 mid.resize(sz+1,-1);
10493 if((INTERP_KERNEL::NormalizedCellType)c[ci[i]]==INTERP_KERNEL::NORM_SEG3)
10495 middleNeedsToBeUsed=true;
10496 const std::vector<int>& candidates(overlapEdge[i]);
10497 std::vector<int> trueCandidates;
10498 for(std::vector<int>::const_iterator itc=candidates.begin();itc!=candidates.end();itc++)
10499 if((INTERP_KERNEL::NormalizedCellType)c[ci[*itc]]==INTERP_KERNEL::NORM_SEG3)
10500 trueCandidates.push_back(*itc);
10501 int stNode(c[ci[i]+1]),endNode(isect[0]);
10502 for(int j=0;j<sz+1;j++)
10504 for(std::vector<int>::const_iterator itc=trueCandidates.begin();itc!=trueCandidates.end();itc++)
10506 int tmpSt(c[ci[*itc]+1]),tmpEnd(c[ci[*itc]+2]);
10507 if((tmpSt==stNode && tmpEnd==endNode) || (tmpSt==endNode && tmpEnd==stNode))
10508 { mid[j]=*itc; break; }
10511 endNode=j<sz-1?isect[j+1]:c[ci[i]+2];
10516 MCAuto<DataArrayInt> ret(DataArrayInt::New()),notRet(DataArrayInt::New()); ret->alloc(nbOf2DCellsToBeSplit,1);
10517 if(nbOf2DCellsToBeSplit==0)
10520 int *retPtr(ret->getPointer());
10521 for(int i=0;i<nCell;i++)
10522 if(cells2DToTreat[i])
10525 MCAuto<DataArrayInt> mSafe,nSafe,oSafe,pSafe,qSafe,rSafe;
10526 DataArrayInt *m(0),*n(0),*o(0),*p(0),*q(0),*r(0);
10527 MEDCouplingUMesh::ExtractFromIndexedArrays(ret->begin(),ret->end(),desc1,descIndx1,m,n); mSafe=m; nSafe=n;
10528 DataArrayInt::PutIntoToSkylineFrmt(intersectEdge,o,p); oSafe=o; pSafe=p;
10529 if(middleNeedsToBeUsed)
10530 { DataArrayInt::PutIntoToSkylineFrmt(middle,q,r); qSafe=q; rSafe=r; }
10531 MCAuto<MEDCouplingUMesh> modif(static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(ret->begin(),ret->end(),true)));
10532 int nbOfNodesCreated(modif->split2DCells(mSafe,nSafe,oSafe,pSafe,qSafe,rSafe));
10533 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.
10534 setPartOfMySelf(ret->begin(),ret->end(),*modif);
10536 bool areNodesMerged; int newNbOfNodes;
10537 if(nbOfNodesCreated!=0)
10538 MCAuto<DataArrayInt> tmp(mergeNodes(eps,areNodesMerged,newNbOfNodes));
10544 * 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.
10545 * 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).
10546 * 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
10547 * to invoke MEDCouplingUMesh::mergeNodes and MEDCouplingUMesh::conformize2D right after this call.
10548 * 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
10549 * new nodes for center of merged edges is are systematically created and appended at the end of the previously existing nodes.
10551 * 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
10552 * using new instance, idem for coordinates.
10554 * 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.
10556 * \return DataArrayInt * - The list of cellIds in \a this that have at least one edge colinearized.
10558 * \throw If \a this is not coherent.
10559 * \throw If \a this has not spaceDim equal to 2.
10560 * \throw If \a this has not meshDim equal to 2.
10562 * \sa MEDCouplingUMesh::conformize2D, MEDCouplingUMesh::mergeNodes, MEDCouplingUMesh::convexEnvelop2D.
10564 DataArrayInt *MEDCouplingUMesh::colinearize2D(double eps)
10566 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
10567 checkConsistencyLight();
10568 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10569 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::colinearize2D : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10570 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10571 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10572 int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
10573 const int *cptr(_nodal_connec->begin()),*ciptr(_nodal_connec_index->begin());
10574 MCAuto<DataArrayInt> newc(DataArrayInt::New()),newci(DataArrayInt::New()); newci->alloc(nbOfCells+1,1); newc->alloc(0,1); newci->setIJ(0,0,0);
10575 MCAuto<DataArrayDouble> appendedCoords(DataArrayDouble::New()); appendedCoords->alloc(0,1);//1 not 2 it is not a bug.
10576 const double *coords(_coords->begin());
10577 int *newciptr(newci->getPointer());
10578 for(int i=0;i<nbOfCells;i++,newciptr++,ciptr++)
10580 if(Colinearize2DCell(coords,cptr+ciptr[0],cptr+ciptr[1],nbOfNodes,newc,appendedCoords))
10581 ret->pushBackSilent(i);
10582 newciptr[1]=newc->getNumberOfTuples();
10587 if(!appendedCoords->empty())
10589 appendedCoords->rearrange(2);
10590 MCAuto<DataArrayDouble> newCoords(DataArrayDouble::Aggregate(getCoords(),appendedCoords));//treat info on components
10592 setCoords(newCoords);
10595 setConnectivity(newc,newci,true);
10600 * \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.
10601 * 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.
10602 * And for each j in [1,n) intersect[i][2*(j-1)+1]==intersect[i][2*j].
10603 * \param [out] subDiv2 - for each cell in \a m2Desc returns nodes that split it using convention \a m1Desc first, then \a m2Desc, then addCoo
10604 * \param [out] colinear2 - for each cell in \a m2Desc returns the edges in \a m1Desc that are colinear to it.
10605 * \param [out] addCoo - nodes to be append at the end
10606 * \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.
10608 void MEDCouplingUMesh::Intersect1DMeshes(const MEDCouplingUMesh *m1Desc, const MEDCouplingUMesh *m2Desc, double eps,
10609 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)
10611 static const int SPACEDIM=2;
10612 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10613 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10614 const int *c1(m1Desc->getNodalConnectivity()->getConstPointer()),*ci1(m1Desc->getNodalConnectivityIndex()->getConstPointer());
10615 // Build BB tree of all edges in the tool mesh (second mesh)
10616 MCAuto<DataArrayDouble> bbox1Arr(m1Desc->getBoundingBoxForBBTree()),bbox2Arr(m2Desc->getBoundingBoxForBBTree());
10617 const double *bbox1(bbox1Arr->begin()),*bbox2(bbox2Arr->begin());
10618 int nDescCell1(m1Desc->getNumberOfCells()),nDescCell2(m2Desc->getNumberOfCells());
10619 intersectEdge1.resize(nDescCell1);
10620 colinear2.resize(nDescCell2);
10621 subDiv2.resize(nDescCell2);
10622 BBTree<SPACEDIM,int> myTree(bbox2,0,0,m2Desc->getNumberOfCells(),-eps);
10624 std::vector<int> candidates1(1);
10625 int offset1(m1Desc->getNumberOfNodes());
10626 int offset2(offset1+m2Desc->getNumberOfNodes());
10627 for(int i=0;i<nDescCell1;i++) // for all edges in the first mesh
10629 std::vector<int> candidates2; // edges of mesh2 candidate for intersection
10630 myTree.getIntersectingElems(bbox1+i*2*SPACEDIM,candidates2);
10631 if(!candidates2.empty()) // candidates2 holds edges from the second mesh potentially intersecting current edge i in mesh1
10633 std::map<INTERP_KERNEL::Node *,int> map1,map2;
10634 // pol2 is not necessarily a closed polygon: just a set of (quadratic) edges (same as candidates2) in the Geometric DS format
10635 INTERP_KERNEL::QuadraticPolygon *pol2=MEDCouplingUMeshBuildQPFromMesh(m2Desc,candidates2,map2);
10637 INTERP_KERNEL::QuadraticPolygon *pol1=MEDCouplingUMeshBuildQPFromMesh(m1Desc,candidates1,map1);
10638 // 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
10639 // This trick guarantees that Node * are discriminant (i.e. form a unique identifier)
10640 std::set<INTERP_KERNEL::Node *> nodes;
10641 pol1->getAllNodes(nodes); pol2->getAllNodes(nodes);
10642 std::size_t szz(nodes.size());
10643 std::vector< MCAuto<INTERP_KERNEL::Node> > nodesSafe(szz);
10644 std::set<INTERP_KERNEL::Node *>::const_iterator itt(nodes.begin());
10645 for(std::size_t iii=0;iii<szz;iii++,itt++)
10646 { (*itt)->incrRef(); nodesSafe[iii]=*itt; }
10647 // end of protection
10648 // Performs egde cutting:
10649 pol1->splitAbs(*pol2,map1,map2,offset1,offset2,candidates2,intersectEdge1[i],i,colinear2,subDiv2,addCoo,mergedNodes);
10654 // Copy the edge (take only the two first points, ie discard quadratic point at this stage)
10655 intersectEdge1[i].insert(intersectEdge1[i].end(),c1+ci1[i]+1,c1+ci1[i]+3);
10660 * This method is private and is the first step of Partition of 2D mesh (spaceDim==2 and meshDim==2).
10661 * It builds the descending connectivity of the two meshes, and then using a binary tree
10662 * it computes the edge intersections. This results in new points being created : they're stored in addCoo.
10663 * Documentation about parameters colinear2 and subDiv2 can be found in method QuadraticPolygon::splitAbs().
10665 void MEDCouplingUMesh::IntersectDescending2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2, double eps,
10666 std::vector< std::vector<int> >& intersectEdge1, std::vector< std::vector<int> >& colinear2, std::vector< std::vector<int> >& subDiv2,
10667 MEDCouplingUMesh *& m1Desc, DataArrayInt *&desc1, DataArrayInt *&descIndx1, DataArrayInt *&revDesc1, DataArrayInt *&revDescIndx1,
10668 std::vector<double>& addCoo,
10669 MEDCouplingUMesh *& m2Desc, DataArrayInt *&desc2, DataArrayInt *&descIndx2, DataArrayInt *&revDesc2, DataArrayInt *&revDescIndx2)
10671 // Build desc connectivity
10672 desc1=DataArrayInt::New(); descIndx1=DataArrayInt::New(); revDesc1=DataArrayInt::New(); revDescIndx1=DataArrayInt::New();
10673 desc2=DataArrayInt::New();
10674 descIndx2=DataArrayInt::New();
10675 revDesc2=DataArrayInt::New();
10676 revDescIndx2=DataArrayInt::New();
10677 MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(revDesc1),dd4(revDescIndx1);
10678 MCAuto<DataArrayInt> dd5(desc2),dd6(descIndx2),dd7(revDesc2),dd8(revDescIndx2);
10679 m1Desc=m1->buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1);
10680 m2Desc=m2->buildDescendingConnectivity2(desc2,descIndx2,revDesc2,revDescIndx2);
10681 MCAuto<MEDCouplingUMesh> dd9(m1Desc),dd10(m2Desc);
10682 std::map<int,int> notUsedMap;
10683 Intersect1DMeshes(m1Desc,m2Desc,eps,intersectEdge1,colinear2,subDiv2,addCoo,notUsedMap);
10684 m1Desc->incrRef(); desc1->incrRef(); descIndx1->incrRef(); revDesc1->incrRef(); revDescIndx1->incrRef();
10685 m2Desc->incrRef(); desc2->incrRef(); descIndx2->incrRef(); revDesc2->incrRef(); revDescIndx2->incrRef();
10689 * This method performs the 2nd step of Partition of 2D mesh.
10690 * This method has 4 inputs :
10691 * - a mesh 'm1' with meshDim==1 and a SpaceDim==2
10692 * - a mesh 'm2' with meshDim==1 and a SpaceDim==2
10693 * - subDiv of size 'm2->getNumberOfCells()' that lists for each seg cell in 'm' the splitting node ids randomly sorted.
10694 * 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'
10695 * Nodes end up lying consecutively on a cutted edge.
10696 * \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.
10697 * (Only present for its coords in case of 'subDiv' shares some nodes of 'm1')
10698 * \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.
10699 * \param addCoo input parameter with additional nodes linked to intersection of the 2 meshes.
10700 * \param[out] intersectEdge the same content as subDiv, but correclty oriented.
10702 void MEDCouplingUMesh::BuildIntersectEdges(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2,
10703 const std::vector<double>& addCoo,
10704 const std::vector< std::vector<int> >& subDiv, std::vector< std::vector<int> >& intersectEdge)
10706 int offset1=m1->getNumberOfNodes();
10707 int ncell=m2->getNumberOfCells();
10708 const int *c=m2->getNodalConnectivity()->getConstPointer();
10709 const int *cI=m2->getNodalConnectivityIndex()->getConstPointer();
10710 const double *coo=m2->getCoords()->getConstPointer();
10711 const double *cooBis=m1->getCoords()->getConstPointer();
10712 int offset2=offset1+m2->getNumberOfNodes();
10713 intersectEdge.resize(ncell);
10714 for(int i=0;i<ncell;i++,cI++)
10716 const std::vector<int>& divs=subDiv[i];
10717 int nnode=cI[1]-cI[0]-1;
10718 std::map<int, std::pair<INTERP_KERNEL::Node *,bool> > mapp2;
10719 std::map<INTERP_KERNEL::Node *, int> mapp22;
10720 for(int j=0;j<nnode;j++)
10722 INTERP_KERNEL::Node *nn=new INTERP_KERNEL::Node(coo[2*c[(*cI)+j+1]],coo[2*c[(*cI)+j+1]+1]);
10723 int nnid=c[(*cI)+j+1];
10724 mapp2[nnid]=std::pair<INTERP_KERNEL::Node *,bool>(nn,true);
10725 mapp22[nn]=nnid+offset1;
10727 INTERP_KERNEL::Edge *e=MEDCouplingUMeshBuildQPFromEdge((INTERP_KERNEL::NormalizedCellType)c[*cI],mapp2,c+(*cI)+1);
10728 for(std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >::const_iterator it=mapp2.begin();it!=mapp2.end();it++)
10729 ((*it).second.first)->decrRef();
10730 std::vector<INTERP_KERNEL::Node *> addNodes(divs.size());
10731 std::map<INTERP_KERNEL::Node *,int> mapp3;
10732 for(std::size_t j=0;j<divs.size();j++)
10735 INTERP_KERNEL::Node *tmp=0;
10737 tmp=new INTERP_KERNEL::Node(cooBis[2*id],cooBis[2*id+1]);
10738 else if(id<offset2)
10739 tmp=new INTERP_KERNEL::Node(coo[2*(id-offset1)],coo[2*(id-offset1)+1]);//if it happens, bad news mesh 'm2' is non conform.
10741 tmp=new INTERP_KERNEL::Node(addCoo[2*(id-offset2)],addCoo[2*(id-offset2)+1]);
10745 e->sortIdsAbs(addNodes,mapp22,mapp3,intersectEdge[i]);
10746 for(std::vector<INTERP_KERNEL::Node *>::const_iterator it=addNodes.begin();it!=addNodes.end();it++)
10753 * 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).
10754 * 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
10755 * with a plane. The result will be put in 'cut3DSuf' out parameter.
10756 * \param [in] cut3DCurve input paramter that gives for each 3DCurve cell if it owns fully to the plane or partially.
10757 * \param [out] nodesOnPlane, returns all the nodes that are on the plane.
10758 * \param [in] nodal3DSurf is the nodal connectivity of 3D surf mesh.
10759 * \param [in] nodalIndx3DSurf is the nodal connectivity index of 3D surf mesh.
10760 * \param [in] nodal3DCurve is the nodal connectivity of 3D curve mesh.
10761 * \param [in] nodal3DIndxCurve is the nodal connectivity index of 3D curve mesh.
10762 * \param [in] desc is the descending connectivity 3DSurf->3DCurve
10763 * \param [in] descIndx is the descending connectivity index 3DSurf->3DCurve
10764 * \param [out] cut3DSuf input/output param.
10766 void MEDCouplingUMesh::AssemblyForSplitFrom3DCurve(const std::vector<int>& cut3DCurve, std::vector<int>& nodesOnPlane, const int *nodal3DSurf, const int *nodalIndx3DSurf,
10767 const int *nodal3DCurve, const int *nodalIndx3DCurve,
10768 const int *desc, const int *descIndx,
10769 std::vector< std::pair<int,int> >& cut3DSurf)
10771 std::set<int> nodesOnP(nodesOnPlane.begin(),nodesOnPlane.end());
10772 int nbOf3DSurfCell=(int)cut3DSurf.size();
10773 for(int i=0;i<nbOf3DSurfCell;i++)
10775 std::vector<int> res;
10776 int offset=descIndx[i];
10777 int nbOfSeg=descIndx[i+1]-offset;
10778 for(int j=0;j<nbOfSeg;j++)
10780 int edgeId=desc[offset+j];
10781 int status=cut3DCurve[edgeId];
10785 res.push_back(status);
10788 res.push_back(nodal3DCurve[nodalIndx3DCurve[edgeId]+1]);
10789 res.push_back(nodal3DCurve[nodalIndx3DCurve[edgeId]+2]);
10797 cut3DSurf[i].first=res[0]; cut3DSurf[i].second=res[1];
10803 std::set<int> s1(nodal3DSurf+nodalIndx3DSurf[i]+1,nodal3DSurf+nodalIndx3DSurf[i+1]);
10804 std::set_intersection(nodesOnP.begin(),nodesOnP.end(),s1.begin(),s1.end(),std::back_insert_iterator< std::vector<int> >(res));
10807 cut3DSurf[i].first=res[0]; cut3DSurf[i].second=res[1];
10811 cut3DSurf[i].first=-1; cut3DSurf[i].second=-1;
10816 {// case when plane is on a multi colinear edge of a polyhedron
10817 if((int)res.size()==2*nbOfSeg)
10819 cut3DSurf[i].first=-2; cut3DSurf[i].second=i;
10822 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AssemblyPointsFrom3DCurve : unexpected situation !");
10829 * \a this is expected to be a mesh with spaceDim==3 and meshDim==3. If not an exception will be thrown.
10830 * 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).
10831 * 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
10832 * with a plane. The result will be put in 'nodalRes' 'nodalResIndx' and 'cellIds' out parameters.
10833 * \param cut3DSurf input paramter that gives for each 3DSurf its intersection with plane (result of MEDCouplingUMesh::AssemblyForSplitFrom3DCurve).
10834 * \param desc is the descending connectivity 3D->3DSurf
10835 * \param descIndx is the descending connectivity index 3D->3DSurf
10837 void MEDCouplingUMesh::assemblyForSplitFrom3DSurf(const std::vector< std::pair<int,int> >& cut3DSurf,
10838 const int *desc, const int *descIndx,
10839 DataArrayInt *nodalRes, DataArrayInt *nodalResIndx, DataArrayInt *cellIds) const
10841 checkFullyDefined();
10842 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
10843 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::assemblyForSplitFrom3DSurf works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
10844 const int *nodal3D(_nodal_connec->begin()),*nodalIndx3D(_nodal_connec_index->begin());
10845 int nbOfCells(getNumberOfCells());
10846 for(int i=0;i<nbOfCells;i++)
10848 std::map<int, std::set<int> > m;
10849 int offset=descIndx[i];
10850 int nbOfFaces=descIndx[i+1]-offset;
10853 for(int j=0;j<nbOfFaces;j++)
10855 const std::pair<int,int>& p=cut3DSurf[desc[offset+j]];
10856 if(p.first!=-1 && p.second!=-1)
10860 start=p.first; end=p.second;
10861 m[p.first].insert(p.second);
10862 m[p.second].insert(p.first);
10866 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodal3D[nodalIndx3D[i]]);
10867 int sz=nodalIndx3D[i+1]-nodalIndx3D[i]-1;
10868 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
10869 INTERP_KERNEL::NormalizedCellType cmsId;
10870 unsigned nbOfNodesSon=cm.fillSonCellNodalConnectivity2(j,nodal3D+nodalIndx3D[i]+1,sz,tmp,cmsId);
10871 start=tmp[0]; end=tmp[nbOfNodesSon-1];
10872 for(unsigned k=0;k<nbOfNodesSon;k++)
10874 m[tmp[k]].insert(tmp[(k+1)%nbOfNodesSon]);
10875 m[tmp[(k+1)%nbOfNodesSon]].insert(tmp[k]);
10882 std::vector<int> conn(1,(int)INTERP_KERNEL::NORM_POLYGON);
10886 std::map<int, std::set<int> >::const_iterator it=m.find(start);
10887 const std::set<int>& s=(*it).second;
10888 std::set<int> s2; s2.insert(prev);
10890 std::set_difference(s.begin(),s.end(),s2.begin(),s2.end(),inserter(s3,s3.begin()));
10893 int val=*s3.begin();
10894 conn.push_back(start);
10901 conn.push_back(end);
10904 nodalRes->insertAtTheEnd(conn.begin(),conn.end());
10905 nodalResIndx->pushBackSilent(nodalRes->getNumberOfTuples());
10906 cellIds->pushBackSilent(i);
10911 void InsertNodeInConnIfNecessary(int nodeIdToInsert, std::vector<int>& conn, const double *coords, double eps)
10913 std::vector<int>::iterator it(std::find(conn.begin(),conn.end(),nodeIdToInsert));
10916 std::size_t sz(conn.size());
10917 std::size_t found(std::numeric_limits<std::size_t>::max());
10918 for(std::size_t i=0;i<sz;i++)
10920 int pt0(conn[i]),pt1(conn[(i+1)%sz]);
10921 double v1[3]={coords[3*pt1+0]-coords[3*pt0+0],coords[3*pt1+1]-coords[3*pt0+1],coords[3*pt1+2]-coords[3*pt0+2]},v2[3]={coords[3*nodeIdToInsert+0]-coords[3*pt0+0],coords[3*nodeIdToInsert+1]-coords[3*pt0+1],coords[3*nodeIdToInsert+2]-coords[3*pt0+2]};
10922 double normm(sqrt(v1[0]*v1[0]+v1[1]*v1[1]+v1[2]*v1[2]));
10923 std::transform(v1,v1+3,v1,std::bind2nd(std::multiplies<double>(),1./normm));
10924 std::transform(v2,v2+3,v2,std::bind2nd(std::multiplies<double>(),1./normm));
10926 v3[0]=v1[1]*v2[2]-v1[2]*v2[1]; v3[1]=v1[2]*v2[0]-v1[0]*v2[2]; v3[2]=v1[0]*v2[1]-v1[1]*v2[0];
10927 double normm2(sqrt(v3[0]*v3[0]+v3[1]*v3[1]+v3[2]*v3[2])),dotTest(v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2]);
10929 if(dotTest>eps && dotTest<1.-eps)
10935 if(found==std::numeric_limits<std::size_t>::max())
10936 throw INTERP_KERNEL::Exception("InsertNodeInConnIfNecessary : not found point !");
10937 conn.insert(conn.begin()+(found+1)%sz,nodeIdToInsert);
10940 void SplitIntoToPart(const std::vector<int>& conn, int pt0, int pt1, std::vector<int>& part0, std::vector<int>& part1)
10942 std::size_t sz(conn.size());
10943 std::vector<int> *curPart(&part0);
10944 for(std::size_t i=0;i<sz;i++)
10946 int nextt(conn[(i+1)%sz]);
10947 (*curPart).push_back(nextt);
10948 if(nextt==pt0 || nextt==pt1)
10950 if(curPart==&part0)
10954 (*curPart).push_back(nextt);
10960 * this method method splits cur cells 3D Surf in sub cells 3DSurf using the previous subsplit. This method is the last one used to clip.
10962 void MEDCouplingUMesh::buildSubCellsFromCut(const std::vector< std::pair<int,int> >& cut3DSurf,
10963 const int *desc, const int *descIndx, const double *coords, double eps,
10964 std::vector<std::vector<int> >& res) const
10966 checkFullyDefined();
10967 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
10968 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSubCellsFromCut works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
10969 const int *nodal3D(_nodal_connec->begin()),*nodalIndx3D(_nodal_connec_index->begin());
10970 int nbOfCells(getNumberOfCells());
10972 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSubCellsFromCut works only with single cell presently !");
10973 for(int i=0;i<nbOfCells;i++)
10975 int offset(descIndx[i]),nbOfFaces(descIndx[i+1]-offset),start(-1),end(-1);
10976 for(int j=0;j<nbOfFaces;j++)
10978 const std::pair<int,int>& p=cut3DSurf[desc[offset+j]];
10979 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodal3D[nodalIndx3D[i]]));
10980 int sz=nodalIndx3D[i+1]-nodalIndx3D[i]-1;
10981 INTERP_KERNEL::AutoPtr<int> tmp(new int[sz]);
10982 INTERP_KERNEL::NormalizedCellType cmsId;
10983 unsigned nbOfNodesSon(cm.fillSonCellNodalConnectivity2(j,nodal3D+nodalIndx3D[i]+1,sz,tmp,cmsId));
10984 std::vector<int> elt((int *)tmp,(int *)tmp+nbOfNodesSon);
10985 if(p.first!=-1 && p.second!=-1)
10989 InsertNodeInConnIfNecessary(p.first,elt,coords,eps);
10990 InsertNodeInConnIfNecessary(p.second,elt,coords,eps);
10991 std::vector<int> elt1,elt2;
10992 SplitIntoToPart(elt,p.first,p.second,elt1,elt2);
10993 res.push_back(elt1);
10994 res.push_back(elt2);
10997 res.push_back(elt);
11000 res.push_back(elt);
11006 * 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
11007 * 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
11008 * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
11009 * 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
11010 * 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.
11012 * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
11014 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const int *nodalConnBg, const int *nodalConnEnd, DataArrayInt *nodalConnecOut)
11016 std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
11019 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
11020 if(cm.getDimension()==2)
11022 const int *node=nodalConnBg+1;
11023 int startNode=*node++;
11024 double refX=coords[2*startNode];
11025 for(;node!=nodalConnEnd;node++)
11027 if(coords[2*(*node)]<refX)
11030 refX=coords[2*startNode];
11033 std::vector<int> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
11037 double angle0=-M_PI/2;
11042 double angleNext=0.;
11043 while(nextNode!=startNode)
11047 for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
11049 if(*node!=tmpOut.back() && *node!=prevNode)
11051 tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
11052 double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
11057 res=angle0-angleM+2.*M_PI;
11066 if(nextNode!=startNode)
11068 angle0=angleNext-M_PI;
11071 prevNode=tmpOut.back();
11072 tmpOut.push_back(nextNode);
11075 std::vector<int> tmp3(2*(sz-1));
11076 std::vector<int>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
11077 std::copy(nodalConnBg+1,nodalConnEnd,it);
11078 if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
11080 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
11083 if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
11085 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
11090 nodalConnecOut->pushBackSilent((int)INTERP_KERNEL::NORM_POLYGON);
11091 nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
11096 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
11099 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
11103 * This method works on an input pair (\b arr, \b arrIndx) where \b arr indexes is in \b arrIndx.
11104 * 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.
11106 * \param [in] idsToRemoveBg begin of set of ids to remove in \b arr (included)
11107 * \param [in] idsToRemoveEnd end of set of ids to remove in \b arr (excluded)
11108 * \param [in,out] arr array in which the remove operation will be done.
11109 * \param [in,out] arrIndx array in the remove operation will modify
11110 * \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])
11111 * \return true if \b arr and \b arrIndx have been modified, false if not.
11113 bool MEDCouplingUMesh::RemoveIdsFromIndexedArrays(const int *idsToRemoveBg, const int *idsToRemoveEnd, DataArrayInt *arr, DataArrayInt *arrIndx, int offsetForRemoval)
11115 if(!arrIndx || !arr)
11116 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : some input arrays are empty !");
11117 if(offsetForRemoval<0)
11118 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : offsetForRemoval should be >=0 !");
11119 std::set<int> s(idsToRemoveBg,idsToRemoveEnd);
11120 int nbOfGrps=arrIndx->getNumberOfTuples()-1;
11121 int *arrIPtr=arrIndx->getPointer();
11123 int previousArrI=0;
11124 const int *arrPtr=arr->getConstPointer();
11125 std::vector<int> arrOut;//no utility to switch to DataArrayInt because copy always needed
11126 for(int i=0;i<nbOfGrps;i++,arrIPtr++)
11128 if(*arrIPtr-previousArrI>offsetForRemoval)
11130 for(const int *work=arrPtr+previousArrI+offsetForRemoval;work!=arrPtr+*arrIPtr;work++)
11132 if(s.find(*work)==s.end())
11133 arrOut.push_back(*work);
11136 previousArrI=*arrIPtr;
11137 *arrIPtr=(int)arrOut.size();
11139 if(arr->getNumberOfTuples()==(int)arrOut.size())
11141 arr->alloc((int)arrOut.size(),1);
11142 std::copy(arrOut.begin(),arrOut.end(),arr->getPointer());
11147 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
11148 * (\ref numbering-indirect).
11149 * This method returns the result of the extraction ( specified by a set of ids in [\b idsOfSelectBg , \b idsOfSelectEnd ) ).
11150 * The selection of extraction is done standardly in new2old format.
11151 * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
11153 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
11154 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
11155 * \param [in] arrIn arr origin array from which the extraction will be done.
11156 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11157 * \param [out] arrOut the resulting array
11158 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11159 * \sa MEDCouplingUMesh::ExtractFromIndexedArraysSlice
11161 void MEDCouplingUMesh::ExtractFromIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11162 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11164 if(!arrIn || !arrIndxIn)
11165 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input pointer is NULL !");
11166 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
11167 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
11168 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input arrays must have exactly one component !");
11169 std::size_t sz=std::distance(idsOfSelectBg,idsOfSelectEnd);
11170 const int *arrInPtr=arrIn->getConstPointer();
11171 const int *arrIndxPtr=arrIndxIn->getConstPointer();
11172 int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
11174 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
11175 int maxSizeOfArr=arrIn->getNumberOfTuples();
11176 MCAuto<DataArrayInt> arro=DataArrayInt::New();
11177 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11178 arrIo->alloc((int)(sz+1),1);
11179 const int *idsIt=idsOfSelectBg;
11180 int *work=arrIo->getPointer();
11183 for(std::size_t i=0;i<sz;i++,work++,idsIt++)
11185 if(*idsIt>=0 && *idsIt<nbOfGrps)
11186 lgth+=arrIndxPtr[*idsIt+1]-arrIndxPtr[*idsIt];
11189 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " ! Must be in [0," << nbOfGrps << ") !";
11190 throw INTERP_KERNEL::Exception(oss.str());
11196 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " and at this pos arrIndxIn[" << *idsIt;
11197 oss << "+1]-arrIndxIn[" << *idsIt << "] < 0 ! The input index array is bugged !";
11198 throw INTERP_KERNEL::Exception(oss.str());
11201 arro->alloc(lgth,1);
11202 work=arro->getPointer();
11203 idsIt=idsOfSelectBg;
11204 for(std::size_t i=0;i<sz;i++,idsIt++)
11206 if(arrIndxPtr[*idsIt]>=0 && arrIndxPtr[*idsIt+1]<=maxSizeOfArr)
11207 work=std::copy(arrInPtr+arrIndxPtr[*idsIt],arrInPtr+arrIndxPtr[*idsIt+1],work);
11210 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " arrIndx[" << *idsIt << "] must be >= 0 and arrIndx[";
11211 oss << *idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
11212 throw INTERP_KERNEL::Exception(oss.str());
11215 arrOut=arro.retn();
11216 arrIndexOut=arrIo.retn();
11220 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
11221 * (\ref numbering-indirect).
11222 * 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 ).
11223 * The selection of extraction is done standardly in new2old format.
11224 * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
11226 * \param [in] idsOfSelectStart begin of set of ids of the input extraction (included)
11227 * \param [in] idsOfSelectStop end of set of ids of the input extraction (excluded)
11228 * \param [in] idsOfSelectStep
11229 * \param [in] arrIn arr origin array from which the extraction will be done.
11230 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11231 * \param [out] arrOut the resulting array
11232 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11233 * \sa MEDCouplingUMesh::ExtractFromIndexedArrays
11235 void MEDCouplingUMesh::ExtractFromIndexedArraysSlice(int idsOfSelectStart, int idsOfSelectStop, int idsOfSelectStep, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11236 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11238 if(!arrIn || !arrIndxIn)
11239 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input pointer is NULL !");
11240 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
11241 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
11242 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input arrays must have exactly one component !");
11243 int sz=DataArrayInt::GetNumberOfItemGivenBESRelative(idsOfSelectStart,idsOfSelectStop,idsOfSelectStep,"MEDCouplingUMesh::ExtractFromIndexedArraysSlice : Input slice ");
11244 const int *arrInPtr=arrIn->getConstPointer();
11245 const int *arrIndxPtr=arrIndxIn->getConstPointer();
11246 int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
11248 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
11249 int maxSizeOfArr=arrIn->getNumberOfTuples();
11250 MCAuto<DataArrayInt> arro=DataArrayInt::New();
11251 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11252 arrIo->alloc((int)(sz+1),1);
11253 int idsIt=idsOfSelectStart;
11254 int *work=arrIo->getPointer();
11257 for(int i=0;i<sz;i++,work++,idsIt+=idsOfSelectStep)
11259 if(idsIt>=0 && idsIt<nbOfGrps)
11260 lgth+=arrIndxPtr[idsIt+1]-arrIndxPtr[idsIt];
11263 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " ! Must be in [0," << nbOfGrps << ") !";
11264 throw INTERP_KERNEL::Exception(oss.str());
11270 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " and at this pos arrIndxIn[" << idsIt;
11271 oss << "+1]-arrIndxIn[" << idsIt << "] < 0 ! The input index array is bugged !";
11272 throw INTERP_KERNEL::Exception(oss.str());
11275 arro->alloc(lgth,1);
11276 work=arro->getPointer();
11277 idsIt=idsOfSelectStart;
11278 for(int i=0;i<sz;i++,idsIt+=idsOfSelectStep)
11280 if(arrIndxPtr[idsIt]>=0 && arrIndxPtr[idsIt+1]<=maxSizeOfArr)
11281 work=std::copy(arrInPtr+arrIndxPtr[idsIt],arrInPtr+arrIndxPtr[idsIt+1],work);
11284 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " arrIndx[" << idsIt << "] must be >= 0 and arrIndx[";
11285 oss << idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
11286 throw INTERP_KERNEL::Exception(oss.str());
11289 arrOut=arro.retn();
11290 arrIndexOut=arrIo.retn();
11294 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11295 * 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
11296 * cellIds \b in [ \b idsOfSelectBg , \b idsOfSelectEnd ) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
11297 * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
11299 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
11300 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
11301 * \param [in] arrIn arr origin array from which the extraction will be done.
11302 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11303 * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg, \b idsOfSelectEnd )
11304 * \param [in] srcArrIndex index array of \b srcArr
11305 * \param [out] arrOut the resulting array
11306 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11308 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
11310 void MEDCouplingUMesh::SetPartOfIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11311 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
11312 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11314 if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11315 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArrays : presence of null pointer in input parameter !");
11316 MCAuto<DataArrayInt> arro=DataArrayInt::New();
11317 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11318 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11319 std::vector<bool> v(nbOfTuples,true);
11321 const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11322 const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11323 for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
11325 if(*it>=0 && *it<nbOfTuples)
11328 offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[*it+1]-arrIndxInPtr[*it]);
11332 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArrays : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
11333 throw INTERP_KERNEL::Exception(oss.str());
11336 srcArrIndexPtr=srcArrIndex->getConstPointer();
11337 arrIo->alloc(nbOfTuples+1,1);
11338 arro->alloc(arrIn->getNumberOfTuples()+offset,1);
11339 const int *arrInPtr=arrIn->getConstPointer();
11340 const int *srcArrPtr=srcArr->getConstPointer();
11341 int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
11342 int *arroPtr=arro->getPointer();
11343 for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
11347 arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
11348 *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
11352 std::size_t pos=std::distance(idsOfSelectBg,std::find(idsOfSelectBg,idsOfSelectEnd,ii));
11353 arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
11354 *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
11357 arrOut=arro.retn();
11358 arrIndexOut=arrIo.retn();
11362 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11363 * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
11365 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
11366 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
11367 * \param [in,out] arrInOut arr origin array from which the extraction will be done.
11368 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11369 * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg , \b idsOfSelectEnd )
11370 * \param [in] srcArrIndex index array of \b srcArr
11372 * \sa MEDCouplingUMesh::SetPartOfIndexedArrays
11374 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(const int *idsOfSelectBg, const int *idsOfSelectEnd, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
11375 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
11377 if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11378 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : presence of null pointer in input parameter !");
11379 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11380 const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11381 const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11382 int *arrInOutPtr=arrInOut->getPointer();
11383 const int *srcArrPtr=srcArr->getConstPointer();
11384 for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
11386 if(*it>=0 && *it<nbOfTuples)
11388 if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[*it+1]-arrIndxInPtr[*it])
11389 std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[*it]);
11392 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] !";
11393 throw INTERP_KERNEL::Exception(oss.str());
11398 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
11399 throw INTERP_KERNEL::Exception(oss.str());
11405 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
11406 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
11407 * 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]].
11408 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
11409 * A negative value in \b arrIn means that it is ignored.
11410 * 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.
11412 * \param [in] arrIn arr origin array from which the extraction will be done.
11413 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11414 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
11415 * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
11417 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn)
11419 int seed=0,nbOfDepthPeelingPerformed=0;
11420 return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
11424 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
11425 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
11426 * 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]].
11427 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
11428 * A negative value in \b arrIn means that it is ignored.
11429 * 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.
11430 * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
11431 * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
11432 * \param [in] arrIn arr origin array from which the extraction will be done.
11433 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11434 * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
11435 * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
11436 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
11437 * \sa MEDCouplingUMesh::partitionBySpreadZone
11439 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed)
11441 nbOfDepthPeelingPerformed=0;
11443 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
11444 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11447 DataArrayInt *ret=DataArrayInt::New(); ret->alloc(0,1);
11451 std::vector<bool> fetched(nbOfTuples,false);
11452 return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
11455 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg(std::vector<bool>& fetched, const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed)
11457 nbOfDepthPeelingPerformed=0;
11458 if(!seedBg || !seedEnd || !arrIn || !arrIndxIn)
11459 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg : some input pointer is NULL !");
11460 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11461 std::vector<bool> fetched2(nbOfTuples,false);
11463 for(const int *seedElt=seedBg;seedElt!=seedEnd;seedElt++,i++)
11465 if(*seedElt>=0 && *seedElt<nbOfTuples)
11466 { fetched[*seedElt]=true; fetched2[*seedElt]=true; }
11468 { 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()); }
11470 const int *arrInPtr=arrIn->getConstPointer();
11471 const int *arrIndxPtr=arrIndxIn->getConstPointer();
11472 int targetNbOfDepthPeeling=nbOfDepthPeeling!=-1?nbOfDepthPeeling:std::numeric_limits<int>::max();
11473 std::vector<int> idsToFetch1(seedBg,seedEnd);
11474 std::vector<int> idsToFetch2;
11475 std::vector<int> *idsToFetch=&idsToFetch1;
11476 std::vector<int> *idsToFetchOther=&idsToFetch2;
11477 while(!idsToFetch->empty() && nbOfDepthPeelingPerformed<targetNbOfDepthPeeling)
11479 for(std::vector<int>::const_iterator it=idsToFetch->begin();it!=idsToFetch->end();it++)
11480 for(const int *it2=arrInPtr+arrIndxPtr[*it];it2!=arrInPtr+arrIndxPtr[*it+1];it2++)
11482 { fetched[*it2]=true; fetched2[*it2]=true; idsToFetchOther->push_back(*it2); }
11483 std::swap(idsToFetch,idsToFetchOther);
11484 idsToFetchOther->clear();
11485 nbOfDepthPeelingPerformed++;
11487 int lgth=(int)std::count(fetched2.begin(),fetched2.end(),true);
11489 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(lgth,1);
11490 int *retPtr=ret->getPointer();
11491 for(std::vector<bool>::const_iterator it=fetched2.begin();it!=fetched2.end();it++,i++)
11498 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11499 * 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
11500 * cellIds \b in [\b idsOfSelectBg, \b idsOfSelectEnd) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
11501 * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
11503 * \param [in] start begin of set of ids of the input extraction (included)
11504 * \param [in] end end of set of ids of the input extraction (excluded)
11505 * \param [in] step step of the set of ids in range mode.
11506 * \param [in] arrIn arr origin array from which the extraction will be done.
11507 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11508 * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
11509 * \param [in] srcArrIndex index array of \b srcArr
11510 * \param [out] arrOut the resulting array
11511 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11513 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx MEDCouplingUMesh::SetPartOfIndexedArrays
11515 void MEDCouplingUMesh::SetPartOfIndexedArraysSlice(int start, int end, int step, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11516 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
11517 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11519 if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11520 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSlice : presence of null pointer in input parameter !");
11521 MCAuto<DataArrayInt> arro=DataArrayInt::New();
11522 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11523 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11525 const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11526 const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11527 int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSlice : ");
11529 for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
11531 if(it>=0 && it<nbOfTuples)
11532 offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[it+1]-arrIndxInPtr[it]);
11535 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
11536 throw INTERP_KERNEL::Exception(oss.str());
11539 srcArrIndexPtr=srcArrIndex->getConstPointer();
11540 arrIo->alloc(nbOfTuples+1,1);
11541 arro->alloc(arrIn->getNumberOfTuples()+offset,1);
11542 const int *arrInPtr=arrIn->getConstPointer();
11543 const int *srcArrPtr=srcArr->getConstPointer();
11544 int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
11545 int *arroPtr=arro->getPointer();
11546 for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
11548 int pos=DataArray::GetPosOfItemGivenBESRelativeNoThrow(ii,start,end,step);
11551 arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
11552 *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
11556 arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
11557 *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
11560 arrOut=arro.retn();
11561 arrIndexOut=arrIo.retn();
11565 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11566 * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
11568 * \param [in] start begin of set of ids of the input extraction (included)
11569 * \param [in] end end of set of ids of the input extraction (excluded)
11570 * \param [in] step step of the set of ids in range mode.
11571 * \param [in,out] arrInOut arr origin array from which the extraction will be done.
11572 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11573 * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
11574 * \param [in] srcArrIndex index array of \b srcArr
11576 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSlice MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
11578 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(int start, int end, int step, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
11579 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
11581 if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11582 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : presence of null pointer in input parameter !");
11583 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11584 const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11585 const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11586 int *arrInOutPtr=arrInOut->getPointer();
11587 const int *srcArrPtr=srcArr->getConstPointer();
11588 int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : ");
11590 for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
11592 if(it>=0 && it<nbOfTuples)
11594 if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[it+1]-arrIndxInPtr[it])
11595 std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[it]);
11598 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " id (idsOfSelectBg[" << i << "]) is " << it << " arrIndxIn[id+1]-arrIndxIn[id]!=srcArrIndex[pos+1]-srcArrIndex[pos] !";
11599 throw INTERP_KERNEL::Exception(oss.str());
11604 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
11605 throw INTERP_KERNEL::Exception(oss.str());
11611 * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
11612 * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
11613 * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
11614 * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
11615 * The sum of measure field of returned mesh is equal to the sum of measure field of this.
11617 * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
11619 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
11621 checkFullyDefined();
11622 int mdim=getMeshDimension();
11623 int spaceDim=getSpaceDimension();
11625 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
11626 std::vector<DataArrayInt *> partition=partitionBySpreadZone();
11627 std::vector< MCAuto<DataArrayInt> > partitionAuto; partitionAuto.reserve(partition.size());
11628 std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayInt> > >(partitionAuto));
11629 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
11630 ret->setCoords(getCoords());
11631 ret->allocateCells((int)partition.size());
11633 for(std::vector<DataArrayInt *>::const_iterator it=partition.begin();it!=partition.end();it++)
11635 MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
11636 MCAuto<DataArrayInt> cell;
11640 cell=tmp->buildUnionOf2DMesh();
11643 cell=tmp->buildUnionOf3DMesh();
11646 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
11649 ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->getConstPointer()+1);
11652 ret->finishInsertingCells();
11657 * This method partitions \b this into contiguous zone.
11658 * This method only needs a well defined connectivity. Coordinates are not considered here.
11659 * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
11661 std::vector<DataArrayInt *> MEDCouplingUMesh::partitionBySpreadZone() const
11663 int nbOfCellsCur=getNumberOfCells();
11664 std::vector<DataArrayInt *> ret;
11665 if(nbOfCellsCur<=0)
11667 DataArrayInt *neigh=0,*neighI=0;
11668 computeNeighborsOfCells(neigh,neighI);
11669 MCAuto<DataArrayInt> neighAuto(neigh),neighIAuto(neighI);
11670 std::vector<bool> fetchedCells(nbOfCellsCur,false);
11671 std::vector< MCAuto<DataArrayInt> > ret2;
11673 while(seed<nbOfCellsCur)
11675 int nbOfPeelPerformed=0;
11676 ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,neigh,neighI,-1,nbOfPeelPerformed));
11677 seed=(int)std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false));
11679 for(std::vector< MCAuto<DataArrayInt> >::iterator it=ret2.begin();it!=ret2.end();it++)
11680 ret.push_back((*it).retn());
11685 * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
11686 * newly allocated DataArrayInt instance with 2 components ready to be interpreted as input of DataArrayInt::findRangeIdForEachTuple method.
11688 * \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.
11689 * \return a newly allocated DataArrayInt to be managed by the caller.
11690 * \throw In case of \a code has not the right format (typically of size 3*n)
11692 DataArrayInt *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<int>& code)
11694 MCAuto<DataArrayInt> ret=DataArrayInt::New();
11695 std::size_t nb=code.size()/3;
11696 if(code.size()%3!=0)
11697 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
11698 ret->alloc((int)nb,2);
11699 int *retPtr=ret->getPointer();
11700 for(std::size_t i=0;i<nb;i++,retPtr+=2)
11702 retPtr[0]=code[3*i+2];
11703 retPtr[1]=code[3*i+2]+code[3*i+1];
11709 * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
11710 * All cells in \a this are expected to be linear 3D cells.
11711 * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
11712 * It leads to an increase to number of cells.
11713 * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
11714 * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
11715 * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
11717 * \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.
11718 * For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
11719 * \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.
11720 * \param [out] n2oCells - A new instance of DataArrayInt holding, for each new cell,
11721 * an id of old cell producing it. The caller is to delete this array using
11722 * decrRef() as it is no more needed.
11723 * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
11725 * \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
11726 * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
11728 * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
11729 * \throw If \a this is not fully constituted with linear 3D cells.
11730 * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
11732 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayInt *& n2oCells, int& nbOfAdditionalPoints) const
11734 INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
11735 checkConnectivityFullyDefined();
11736 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
11737 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
11738 int nbOfCells(getNumberOfCells()),nbNodes(getNumberOfNodes());
11739 MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
11740 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfCells,1);
11741 int *retPt(ret->getPointer());
11742 MCAuto<DataArrayInt> newConn(DataArrayInt::New()); newConn->alloc(0,1);
11743 MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
11744 const int *oldc(_nodal_connec->begin());
11745 const int *oldci(_nodal_connec_index->begin());
11746 const double *coords(_coords->begin());
11747 for(int i=0;i<nbOfCells;i++,oldci++,retPt++)
11749 std::vector<int> a; std::vector<double> b;
11750 INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
11751 std::size_t nbOfTet(a.size()/4); *retPt=(int)nbOfTet;
11752 const int *aa(&a[0]);
11755 for(std::vector<int>::iterator it=a.begin();it!=a.end();it++)
11757 *it=(-(*(it))-1+nbNodes);
11758 addPts->insertAtTheEnd(b.begin(),b.end());
11759 nbNodes+=(int)b.size()/3;
11761 for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
11762 newConn->insertAtTheEnd(aa,aa+4);
11764 if(!addPts->empty())
11766 addPts->rearrange(3);
11767 nbOfAdditionalPoints=addPts->getNumberOfTuples();
11768 addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
11769 ret0->setCoords(addPts);
11773 nbOfAdditionalPoints=0;
11774 ret0->setCoords(getCoords());
11776 ret0->setNodalConnectivity(newConn);
11778 ret->computeOffsetsFull();
11779 n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
11780 return ret0.retn();
11784 * 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).
11786 * \sa MEDCouplingUMesh::split2DCells
11788 void MEDCouplingUMesh::split2DCellsLinear(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI)
11790 checkConnectivityFullyDefined();
11791 int ncells(getNumberOfCells()),lgthToReach(getNodalConnectivityArrayLen()+subNodesInSeg->getNumberOfTuples());
11792 MCAuto<DataArrayInt> c(DataArrayInt::New()); c->alloc((std::size_t)lgthToReach);
11793 const int *subPtr(subNodesInSeg->begin()),*subIPtr(subNodesInSegI->begin()),*descPtr(desc->begin()),*descIPtr(descI->begin()),*oldConn(getNodalConnectivity()->begin());
11794 int *cPtr(c->getPointer()),*ciPtr(getNodalConnectivityIndex()->getPointer());
11795 int prevPosOfCi(ciPtr[0]);
11796 for(int i=0;i<ncells;i++,ciPtr++,descIPtr++)
11798 int offset(descIPtr[0]),sz(descIPtr[1]-descIPtr[0]),deltaSz(0);
11799 *cPtr++=(int)INTERP_KERNEL::NORM_POLYGON; *cPtr++=oldConn[prevPosOfCi+1];
11800 for(int j=0;j<sz;j++)
11802 int offset2(subIPtr[descPtr[offset+j]]),sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]);
11803 for(int k=0;k<sz2;k++)
11804 *cPtr++=subPtr[offset2+k];
11806 *cPtr++=oldConn[prevPosOfCi+j+2];
11809 prevPosOfCi=ciPtr[1];
11810 ciPtr[1]=ciPtr[0]+1+sz+deltaSz;//sz==old nb of nodes because (nb of subedges=nb of nodes for polygons)
11813 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCellsLinear : Some of edges to be split are orphan !");
11814 _nodal_connec->decrRef();
11815 _nodal_connec=c.retn(); _types.clear(); _types.insert(INTERP_KERNEL::NORM_POLYGON);
11818 int InternalAddPoint(const INTERP_KERNEL::Edge *e, int id, const double *coo, int startId, int endId, DataArrayDouble& addCoo, int& nodesCnter)
11824 int ret(nodesCnter++);
11826 e->getMiddleOfPoints(coo+2*startId,coo+2*endId,newPt);
11827 addCoo.insertAtTheEnd(newPt,newPt+2);
11832 int InternalAddPointOriented(const INTERP_KERNEL::Edge *e, int id, const double *coo, int startId, int endId, DataArrayDouble& addCoo, int& nodesCnter)
11838 int ret(nodesCnter++);
11840 e->getMiddleOfPointsOriented(coo+2*startId,coo+2*endId,newPt);
11841 addCoo.insertAtTheEnd(newPt,newPt+2);
11849 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)
11852 int trueStart(start>=0?start:nbOfEdges+start);
11853 tmp[0]=linOrArc?(int)INTERP_KERNEL::NORM_QPOLYG:(int)INTERP_KERNEL::NORM_POLYGON; tmp[1]=connBg[trueStart]; tmp[2]=connBg[stp];
11854 newConnOfCell->insertAtTheEnd(tmp,tmp+3);
11859 int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11860 InternalAddPointOriented(e,-1,coords,tmp[1],tmp[2],*appendedCoords,tmp2);
11861 middles.push_back(tmp3+offset);
11864 middles.push_back(connBg[trueStart+nbOfEdges]);
11868 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)
11870 int tmpSrt(newConnOfCell->back()),tmpEnd(connBg[stp]);
11871 newConnOfCell->pushBackSilent(tmpEnd);
11876 int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11877 InternalAddPointOriented(e,-1,coords,tmpSrt,tmpEnd,*appendedCoords,tmp2);
11878 middles.push_back(tmp3+offset);
11881 middles.push_back(connBg[start+nbOfEdges]);
11885 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)
11887 // only the quadratic point to deal with:
11892 int tmpSrt(connBg[start]),tmpEnd(connBg[stp]);
11893 int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11894 InternalAddPointOriented(e,-1,coords,tmpSrt,tmpEnd,*appendedCoords,tmp2);
11895 middles.push_back(tmp3+offset);
11898 middles.push_back(connBg[start+nbOfEdges]);
11905 * 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 ) .
11906 * \a appendedCoords is a DataArrayDouble instance with number of components equal to one (even if the items are pushed by pair).
11908 bool MEDCouplingUMesh::Colinearize2DCell(const double *coords, const int *connBg, const int *connEnd, int offset, DataArrayInt *newConnOfCell, DataArrayDouble *appendedCoords)
11910 std::size_t sz(std::distance(connBg,connEnd));
11911 if(sz<3)//3 because 2+1(for the cell type) and 2 is the minimal number of edges of 2D cell.
11912 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Colinearize2DCell : the input cell has invalid format !");
11914 INTERP_KERNEL::AutoPtr<int> tmpConn(new int[sz]);
11915 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connBg[0]));
11916 unsigned nbs(cm.getNumberOfSons2(connBg+1,sz));
11917 unsigned nbOfHit(0); // number of fusions operated
11918 int posBaseElt(0),posEndElt(0),nbOfTurn(0);
11919 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
11920 INTERP_KERNEL::NormalizedCellType typeOfSon;
11921 std::vector<int> middles;
11923 for(;(nbOfTurn+nbOfHit)<nbs;nbOfTurn++)
11925 cm.fillSonCellNodalConnectivity2(posBaseElt,connBg+1,sz,tmpConn,typeOfSon);
11926 std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
11927 INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11928 posEndElt = posBaseElt+1;
11930 // Look backward first: are the final edges of the cells colinear with the first ones?
11931 // This initializes posBaseElt.
11934 for(unsigned i=1;i<nbs && nbOfHit<maxNbOfHit;i++) // 2nd condition is to avoid ending with a cell wih one single edge
11936 cm.fillSonCellNodalConnectivity2(nbs-i,connBg+1,sz,tmpConn,typeOfSon);
11937 INTERP_KERNEL::Edge *eCand(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11938 INTERP_KERNEL::EdgeIntersector *eint(INTERP_KERNEL::Edge::BuildIntersectorWith(e,eCand));
11939 bool isColinear=eint->areColinears();
11952 // Now move forward:
11953 const unsigned fwdStart = (nbOfTurn == 0 ? 0 : posBaseElt); // the first element to be inspected going forward
11954 for(unsigned j=fwdStart+1;j<nbs && nbOfHit<maxNbOfHit;j++) // 2nd condition is to avoid ending with a cell wih one single edge
11956 cm.fillSonCellNodalConnectivity2((int)j,connBg+1,sz,tmpConn,typeOfSon); // get edge #j's connectivity
11957 INTERP_KERNEL::Edge *eCand(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11958 INTERP_KERNEL::EdgeIntersector *eint(INTERP_KERNEL::Edge::BuildIntersectorWith(e,eCand));
11959 bool isColinear(eint->areColinears());
11971 //push [posBaseElt,posEndElt) in newConnOfCell using e
11972 // 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!
11974 // at the begining of the connectivity (insert type)
11975 EnterTheResultOf2DCellFirst(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
11976 else if((nbOfHit+nbOfTurn) != (nbs-1))
11978 EnterTheResultOf2DCellMiddle(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
11979 if ((nbOfHit+nbOfTurn) == (nbs-1))
11980 // at the end (only quad points to deal with)
11981 EnterTheResultOf2DCellEnd(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
11982 posBaseElt=posEndElt;
11985 if(!middles.empty())
11986 newConnOfCell->insertAtTheEnd(middles.begin(),middles.end());
11991 * It is the quadratic part of MEDCouplingUMesh::split2DCells. Here some additionnal nodes can be added at the end of coordinates array object.
11993 * \return int - the number of new nodes created.
11994 * \sa MEDCouplingUMesh::split2DCells
11996 int MEDCouplingUMesh::split2DCellsQuadratic(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *mid, const DataArrayInt *midI)
11998 checkConsistencyLight();
11999 int ncells(getNumberOfCells()),lgthToReach(getNodalConnectivityArrayLen()+2*subNodesInSeg->getNumberOfTuples()),nodesCnt(getNumberOfNodes());
12000 MCAuto<DataArrayInt> c(DataArrayInt::New()); c->alloc((std::size_t)lgthToReach);
12001 MCAuto<DataArrayDouble> addCoo(DataArrayDouble::New()); addCoo->alloc(0,1);
12002 const int *subPtr(subNodesInSeg->begin()),*subIPtr(subNodesInSegI->begin()),*descPtr(desc->begin()),*descIPtr(descI->begin()),*oldConn(getNodalConnectivity()->begin());
12003 const int *midPtr(mid->begin()),*midIPtr(midI->begin());
12004 const double *oldCoordsPtr(getCoords()->begin());
12005 int *cPtr(c->getPointer()),*ciPtr(getNodalConnectivityIndex()->getPointer());
12006 int prevPosOfCi(ciPtr[0]);
12007 for(int i=0;i<ncells;i++,ciPtr++,descIPtr++)
12009 int offset(descIPtr[0]),sz(descIPtr[1]-descIPtr[0]),deltaSz(sz);
12010 for(int j=0;j<sz;j++)
12011 { int sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]); deltaSz+=sz2; }
12012 *cPtr++=(int)INTERP_KERNEL::NORM_QPOLYG; cPtr[0]=oldConn[prevPosOfCi+1];
12013 for(int j=0;j<sz;j++)//loop over subedges of oldConn
12015 int offset2(subIPtr[descPtr[offset+j]]),sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]),offset3(midIPtr[descPtr[offset+j]]);
12019 cPtr[1]=oldConn[prevPosOfCi+2+j];
12020 cPtr[deltaSz]=oldConn[prevPosOfCi+1+j+sz]; cPtr++;
12023 std::vector<INTERP_KERNEL::Node *> ns(3);
12024 ns[0]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+j]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+j]+1]);
12025 ns[1]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+(1+j)%sz]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+(1+j)%sz]+1]);
12026 ns[2]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+sz+j]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+sz+j]+1]);
12027 MCAuto<INTERP_KERNEL::Edge> e(INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(ns));
12028 for(int k=0;k<sz2;k++)//loop over subsplit of current subedge
12030 cPtr[1]=subPtr[offset2+k];
12031 cPtr[deltaSz]=InternalAddPoint(e,midPtr[offset3+k],oldCoordsPtr,cPtr[0],cPtr[1],*addCoo,nodesCnt); cPtr++;
12033 int tmpEnd(oldConn[prevPosOfCi+1+(j+1)%sz]);
12035 { cPtr[1]=tmpEnd; }
12036 cPtr[deltaSz]=InternalAddPoint(e,midPtr[offset3+sz2],oldCoordsPtr,cPtr[0],tmpEnd,*addCoo,nodesCnt); cPtr++;
12038 prevPosOfCi=ciPtr[1]; cPtr+=deltaSz;
12039 ciPtr[1]=ciPtr[0]+1+2*deltaSz;//sz==old nb of nodes because (nb of subedges=nb of nodes for polygons)
12042 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCellsQuadratic : Some of edges to be split are orphan !");
12043 _nodal_connec->decrRef();
12044 _nodal_connec=c.retn(); _types.clear(); _types.insert(INTERP_KERNEL::NORM_QPOLYG);
12045 addCoo->rearrange(2);
12046 MCAuto<DataArrayDouble> coo(DataArrayDouble::Aggregate(getCoords(),addCoo));//info are copied from getCoords() by using Aggregate
12048 return addCoo->getNumberOfTuples();
12051 void MEDCouplingUMesh::ComputeAllTypesInternal(std::set<INTERP_KERNEL::NormalizedCellType>& types, const DataArrayInt *nodalConnec, const DataArrayInt *nodalConnecIndex)
12053 if(nodalConnec && nodalConnecIndex)
12056 const int *conn(nodalConnec->getConstPointer()),*connIndex(nodalConnecIndex->getConstPointer());
12057 int nbOfElem(nodalConnecIndex->getNbOfElems()-1);
12059 for(const int *pt=connIndex;pt!=connIndex+nbOfElem;pt++)
12060 types.insert((INTERP_KERNEL::NormalizedCellType)conn[*pt]);
12064 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
12065 _own_cell(true),_cell_id(-1),_nb_cell(0)
12070 _nb_cell=mesh->getNumberOfCells();
12074 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
12082 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_cell(itc),
12083 _own_cell(false),_cell_id(bg-1),
12090 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
12093 if(_cell_id<_nb_cell)
12102 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
12108 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
12110 return new MEDCouplingUMeshCellByTypeIterator(_mesh);
12113 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
12119 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh, INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_type(type),
12127 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
12133 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
12138 int MEDCouplingUMeshCellEntry::getNumberOfElems() const
12143 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
12145 return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
12148 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
12153 _nb_cell=mesh->getNumberOfCells();
12157 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
12164 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
12166 const int *c=_mesh->getNodalConnectivity()->getConstPointer();
12167 const int *ci=_mesh->getNodalConnectivityIndex()->getConstPointer();
12168 if(_cell_id<_nb_cell)
12170 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
12171 int nbOfElems=(int)std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type)));
12172 int startId=_cell_id;
12173 _cell_id+=nbOfElems;
12174 return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
12180 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
12184 _conn=mesh->getNodalConnectivity()->getPointer();
12185 _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
12189 void MEDCouplingUMeshCell::next()
12191 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
12196 _conn_lgth=_conn_indx[1]-_conn_indx[0];
12199 std::string MEDCouplingUMeshCell::repr() const
12201 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
12203 std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
12205 std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<int>(oss," "));
12209 return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
12212 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
12214 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
12215 return (INTERP_KERNEL::NormalizedCellType)_conn[0];
12217 return INTERP_KERNEL::NORM_ERROR;
12220 const int *MEDCouplingUMeshCell::getAllConn(int& lgth) const
12223 if(_conn_lgth!=NOTICABLE_FIRST_VAL)