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 "MEDCouplingMemArray.txx"
24 #include "MEDCouplingFieldDouble.hxx"
25 #include "MEDCouplingSkyLineArray.hxx"
26 #include "CellModel.hxx"
27 #include "VolSurfUser.txx"
28 #include "InterpolationUtils.hxx"
29 #include "PointLocatorAlgos.txx"
31 #include "BBTreeDst.txx"
32 #include "SplitterTetra.hxx"
33 #include "DiameterCalculator.hxx"
34 #include "DirectedBoundingBox.hxx"
35 #include "InterpKernelMatrixTools.hxx"
36 #include "InterpKernelMeshQuality.hxx"
37 #include "InterpKernelCellSimplify.hxx"
38 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
39 #include "InterpKernelAutoPtr.hxx"
40 #include "InterpKernelGeo2DNode.hxx"
41 #include "InterpKernelGeo2DEdgeLin.hxx"
42 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
43 #include "InterpKernelGeo2DQuadraticPolygon.hxx"
52 using namespace MEDCoupling;
54 double MEDCouplingUMesh::EPS_FOR_POLYH_ORIENTATION=1.e-14;
57 const INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::MEDMEM_ORDER[N_MEDMEM_ORDER] = { INTERP_KERNEL::NORM_POINT1, INTERP_KERNEL::NORM_SEG2, INTERP_KERNEL::NORM_SEG3, INTERP_KERNEL::NORM_SEG4, INTERP_KERNEL::NORM_POLYL, INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4, INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_TRI7, INTERP_KERNEL::NORM_QUAD8, INTERP_KERNEL::NORM_QUAD9, INTERP_KERNEL::NORM_POLYGON, INTERP_KERNEL::NORM_QPOLYG, INTERP_KERNEL::NORM_TETRA4, INTERP_KERNEL::NORM_PYRA5, INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXA8, INTERP_KERNEL::NORM_HEXGP12, INTERP_KERNEL::NORM_TETRA10, INTERP_KERNEL::NORM_PYRA13, INTERP_KERNEL::NORM_PENTA15, INTERP_KERNEL::NORM_HEXA20, INTERP_KERNEL::NORM_HEXA27, INTERP_KERNEL::NORM_POLYHED };
60 MEDCouplingUMesh *MEDCouplingUMesh::New()
62 return new MEDCouplingUMesh;
65 MEDCouplingUMesh *MEDCouplingUMesh::New(const std::string& meshName, int meshDim)
67 MEDCouplingUMesh *ret=new MEDCouplingUMesh;
68 ret->setName(meshName);
69 ret->setMeshDimension(meshDim);
74 * Returns a new MEDCouplingUMesh which is a full copy of \a this one. No data is shared
75 * between \a this and the new mesh.
76 * \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
77 * delete this mesh using decrRef() as it is no more needed.
79 MEDCouplingUMesh *MEDCouplingUMesh::deepCopy() const
86 * Returns a new MEDCouplingUMesh which is a copy of \a this one.
87 * \param [in] recDeepCpy - if \a true, the copy is deep, else all data arrays of \a
88 * this mesh are shared by the new mesh.
89 * \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
90 * delete this mesh using decrRef() as it is no more needed.
92 MEDCouplingUMesh *MEDCouplingUMesh::clone(bool recDeepCpy) const
94 return new MEDCouplingUMesh(*this,recDeepCpy);
98 * This method behaves mostly like MEDCouplingUMesh::deepCopy method, except that only nodal connectivity arrays are deeply copied.
99 * The coordinates are shared between \a this and the returned instance.
101 * \return MEDCouplingUMesh * - A new object instance holding the copy of \a this (deep for connectivity, shallow for coordiantes)
102 * \sa MEDCouplingUMesh::deepCopy
104 MEDCouplingUMesh *MEDCouplingUMesh::deepCopyConnectivityOnly() const
106 checkConnectivityFullyDefined();
107 MCAuto<MEDCouplingUMesh> ret=clone(false);
108 MCAuto<DataArrayInt> c(getNodalConnectivity()->deepCopy()),ci(getNodalConnectivityIndex()->deepCopy());
109 ret->setConnectivity(c,ci);
113 void MEDCouplingUMesh::shallowCopyConnectivityFrom(const MEDCouplingPointSet *other)
116 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is null !");
117 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
119 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is not an MEDCouplingUMesh instance !");
120 MEDCouplingUMesh *otherC2=const_cast<MEDCouplingUMesh *>(otherC);//sorry :(
121 setConnectivity(otherC2->getNodalConnectivity(),otherC2->getNodalConnectivityIndex(),true);
124 std::size_t MEDCouplingUMesh::getHeapMemorySizeWithoutChildren() const
126 std::size_t ret(MEDCouplingPointSet::getHeapMemorySizeWithoutChildren());
130 std::vector<const BigMemoryObject *> MEDCouplingUMesh::getDirectChildrenWithNull() const
132 std::vector<const BigMemoryObject *> ret(MEDCouplingPointSet::getDirectChildrenWithNull());
133 ret.push_back(_nodal_connec);
134 ret.push_back(_nodal_connec_index);
138 void MEDCouplingUMesh::updateTime() const
140 MEDCouplingPointSet::updateTime();
143 updateTimeWith(*_nodal_connec);
145 if(_nodal_connec_index)
147 updateTimeWith(*_nodal_connec_index);
151 MEDCouplingUMesh::MEDCouplingUMesh():_mesh_dim(-2),_nodal_connec(0),_nodal_connec_index(0)
156 * Checks if \a this mesh is well defined. If no exception is thrown by this method,
157 * then \a this mesh is most probably is writable, exchangeable and available for most
158 * of algorithms. When a mesh is constructed from scratch, it is a good habit to call
159 * this method to check that all is in order with \a this mesh.
160 * \throw If the mesh dimension is not set.
161 * \throw If the coordinates array is not set (if mesh dimension != -1 ).
162 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
163 * \throw If the connectivity data array has more than one component.
164 * \throw If the connectivity data array has a named component.
165 * \throw If the connectivity index data array has more than one component.
166 * \throw If the connectivity index data array has a named component.
168 void MEDCouplingUMesh::checkConsistencyLight() const
171 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
173 MEDCouplingPointSet::checkConsistencyLight();
174 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
176 if((int)INTERP_KERNEL::CellModel::GetCellModel(*iter).getDimension()!=_mesh_dim)
178 std::ostringstream message;
179 message << "Mesh invalid because dimension is " << _mesh_dim << " and there is presence of cell(s) with type " << (*iter);
180 throw INTERP_KERNEL::Exception(message.str().c_str());
185 if(_nodal_connec->getNumberOfComponents()!=1)
186 throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to be with number of components set to one !");
187 if(_nodal_connec->getInfoOnComponent(0)!="")
188 throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to have no info on its single component !");
192 throw INTERP_KERNEL::Exception("Nodal connectivity array is not defined !");
193 if(_nodal_connec_index)
195 if(_nodal_connec_index->getNumberOfComponents()!=1)
196 throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to be with number of components set to one !");
197 if(_nodal_connec_index->getInfoOnComponent(0)!="")
198 throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to have no info on its single component !");
202 throw INTERP_KERNEL::Exception("Nodal connectivity index array is not defined !");
206 * Checks if \a this mesh is well defined. If no exception is thrown by this method,
207 * then \a this mesh is most probably is writable, exchangeable and available for all
208 * algorithms. <br> In addition to the checks performed by checkConsistencyLight(), this
209 * method thoroughly checks the nodal connectivity.
210 * \param [in] eps - a not used parameter.
211 * \throw If the mesh dimension is not set.
212 * \throw If the coordinates array is not set (if mesh dimension != -1 ).
213 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
214 * \throw If the connectivity data array has more than one component.
215 * \throw If the connectivity data array has a named component.
216 * \throw If the connectivity index data array has more than one component.
217 * \throw If the connectivity index data array has a named component.
218 * \throw If number of nodes defining an element does not correspond to the type of element.
219 * \throw If the nodal connectivity includes an invalid node id.
221 void MEDCouplingUMesh::checkConsistency(double eps) const
223 checkConsistencyLight();
226 int meshDim=getMeshDimension();
227 int nbOfNodes=getNumberOfNodes();
228 int nbOfCells=getNumberOfCells();
229 const int *ptr=_nodal_connec->getConstPointer();
230 const int *ptrI=_nodal_connec_index->getConstPointer();
231 for(int i=0;i<nbOfCells;i++)
233 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)ptr[ptrI[i]]);
234 if((int)cm.getDimension()!=meshDim)
236 std::ostringstream oss;
237 oss << "MEDCouplingUMesh::checkConsistency : cell << #" << i<< " with type Type " << cm.getRepr() << " in 'this' whereas meshdim == " << meshDim << " !";
238 throw INTERP_KERNEL::Exception(oss.str().c_str());
240 int nbOfNodesInCell=ptrI[i+1]-ptrI[i]-1;
242 if(nbOfNodesInCell!=(int)cm.getNumberOfNodes())
244 std::ostringstream oss;
245 oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with static Type '" << cm.getRepr() << "' has " << cm.getNumberOfNodes();
246 oss << " nodes whereas in connectivity there is " << nbOfNodesInCell << " nodes ! Looks very bad !";
247 throw INTERP_KERNEL::Exception(oss.str().c_str());
249 if(cm.isQuadratic() && cm.isDynamic() && meshDim == 2)
250 if (nbOfNodesInCell % 2 || nbOfNodesInCell < 4)
252 std::ostringstream oss;
253 oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with quadratic type '" << cm.getRepr() << "' has " << nbOfNodesInCell;
254 oss << " nodes. This should be even, and greater or equal than 4!! Looks very bad!";
255 throw INTERP_KERNEL::Exception(oss.str().c_str());
257 for(const int *w=ptr+ptrI[i]+1;w!=ptr+ptrI[i+1];w++)
262 if(nodeId>=nbOfNodes)
264 std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " whereas there are only " << nbOfNodes << " nodes in the mesh !";
265 throw INTERP_KERNEL::Exception(oss.str().c_str());
270 std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " in connectivity ! sounds bad !";
271 throw INTERP_KERNEL::Exception(oss.str().c_str());
275 if((INTERP_KERNEL::NormalizedCellType)(ptr[ptrI[i]])!=INTERP_KERNEL::NORM_POLYHED)
277 std::ostringstream oss; oss << "Cell #" << i << " is built with node #-1 in connectivity ! sounds bad !";
278 throw INTERP_KERNEL::Exception(oss.str().c_str());
286 * Sets dimension of \a this mesh. The mesh dimension in general depends on types of
287 * elements contained in the mesh. For more info on the mesh dimension see
288 * \ref MEDCouplingUMeshPage.
289 * \param [in] meshDim - a new mesh dimension.
290 * \throw If \a meshDim is invalid. A valid range is <em> -1 <= meshDim <= 3</em>.
292 void MEDCouplingUMesh::setMeshDimension(int meshDim)
294 if(meshDim<-1 || meshDim>3)
295 throw INTERP_KERNEL::Exception("Invalid meshDim specified ! Must be greater or equal to -1 and lower or equal to 3 !");
301 * Allocates memory to store an estimation of the given number of cells. The closer is the estimation to the number of cells effectively inserted,
302 * the less will the library need to reallocate memory. If the number of cells to be inserted is not known simply put 0 to this parameter.
303 * If a nodal connectivity previouly existed before the call of this method, it will be reset.
305 * \param [in] nbOfCells - estimation of the number of cell \a this mesh will contain.
307 * \if ENABLE_EXAMPLES
308 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
309 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
312 void MEDCouplingUMesh::allocateCells(int nbOfCells)
315 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::allocateCells : the input number of cells should be >= 0 !");
316 if(_nodal_connec_index)
318 _nodal_connec_index->decrRef();
322 _nodal_connec->decrRef();
324 _nodal_connec_index=DataArrayInt::New();
325 _nodal_connec_index->reserve(nbOfCells+1);
326 _nodal_connec_index->pushBackSilent(0);
327 _nodal_connec=DataArrayInt::New();
328 _nodal_connec->reserve(2*nbOfCells);
334 * Appends a cell to the connectivity array. For deeper understanding what is
335 * happening see \ref MEDCouplingUMeshNodalConnectivity.
336 * \param [in] type - type of cell to add.
337 * \param [in] size - number of nodes constituting this cell.
338 * \param [in] nodalConnOfCell - the connectivity of the cell to add.
340 * \if ENABLE_EXAMPLES
341 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
342 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
345 void MEDCouplingUMesh::insertNextCell(INTERP_KERNEL::NormalizedCellType type, int size, const int *nodalConnOfCell)
347 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
348 if(_nodal_connec_index==0)
349 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::insertNextCell : nodal connectivity not set ! invoke allocateCells before calling insertNextCell !");
350 if((int)cm.getDimension()==_mesh_dim)
353 if(size!=(int)cm.getNumberOfNodes())
355 std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : Trying to push a " << cm.getRepr() << " cell with a size of " << size;
356 oss << " ! Expecting " << cm.getNumberOfNodes() << " !";
357 throw INTERP_KERNEL::Exception(oss.str().c_str());
359 int idx=_nodal_connec_index->back();
361 _nodal_connec_index->pushBackSilent(val);
362 _nodal_connec->writeOnPlace(idx,type,nodalConnOfCell,size);
367 std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : cell type " << cm.getRepr() << " has a dimension " << cm.getDimension();
368 oss << " whereas Mesh Dimension of current UMesh instance is set to " << _mesh_dim << " ! Please invoke \"setMeshDimension\" method before or invoke ";
369 oss << "\"MEDCouplingUMesh::New\" static method with 2 parameters name and meshDimension !";
370 throw INTERP_KERNEL::Exception(oss.str().c_str());
375 * Compacts data arrays to release unused memory. This method is to be called after
376 * finishing cell insertion using \a this->insertNextCell().
378 * \if ENABLE_EXAMPLES
379 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
380 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
383 void MEDCouplingUMesh::finishInsertingCells()
385 _nodal_connec->pack();
386 _nodal_connec_index->pack();
387 _nodal_connec->declareAsNew();
388 _nodal_connec_index->declareAsNew();
393 * Entry point for iteration over cells of this. Warning the returned cell iterator should be deallocated.
394 * Useful for python users.
396 MEDCouplingUMeshCellIterator *MEDCouplingUMesh::cellIterator()
398 return new MEDCouplingUMeshCellIterator(this);
402 * Entry point for iteration over cells groups geo types per geotypes. Warning the returned cell iterator should be deallocated.
403 * If \a this is not so that that cells are grouped by geo types this method will throw an exception.
404 * In this case MEDCouplingUMesh::sortCellsInMEDFileFrmt or MEDCouplingUMesh::rearrange2ConsecutiveCellTypes methods for example can be called before invoking this method.
405 * Useful for python users.
407 MEDCouplingUMeshCellByTypeEntry *MEDCouplingUMesh::cellsByType()
409 if(!checkConsecutiveCellTypes())
410 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::cellsByType : this mesh is not sorted by type !");
411 return new MEDCouplingUMeshCellByTypeEntry(this);
415 * Returns a set of all cell types available in \a this mesh.
416 * \return std::set<INTERP_KERNEL::NormalizedCellType> - the set of cell types.
417 * \warning this method does not throw any exception even if \a this is not defined.
418 * \sa MEDCouplingUMesh::getAllGeoTypesSorted
420 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypes() const
426 * This method returns the sorted list of geometric types in \a this.
427 * Sorted means in the same order than the cells in \a this. A single entry in return vector means the maximal chunk of consecutive cells in \a this
428 * having the same geometric type. So a same geometric type can appear more than once if the cells are not sorted per geometric type.
430 * \throw if connectivity in \a this is not correctly defined.
432 * \sa MEDCouplingMesh::getAllGeoTypes
434 std::vector<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypesSorted() const
436 std::vector<INTERP_KERNEL::NormalizedCellType> ret;
437 checkConnectivityFullyDefined();
438 int nbOfCells(getNumberOfCells());
441 if(getNodalConnectivityArrayLen()<1)
442 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAllGeoTypesSorted : the connectivity in this seems invalid !");
443 const int *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin());
444 ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci++]);
445 for(int i=1;i<nbOfCells;i++,ci++)
446 if(ret.back()!=((INTERP_KERNEL::NormalizedCellType)c[*ci]))
447 ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci]);
452 * This method is a method that compares \a this and \a other.
453 * This method compares \b all attributes, even names and component names.
455 bool MEDCouplingUMesh::isEqualIfNotWhy(const MEDCouplingMesh *other, double prec, std::string& reason) const
458 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isEqualIfNotWhy : input other pointer is null !");
459 std::ostringstream oss; oss.precision(15);
460 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
463 reason="mesh given in input is not castable in MEDCouplingUMesh !";
466 if(!MEDCouplingPointSet::isEqualIfNotWhy(other,prec,reason))
468 if(_mesh_dim!=otherC->_mesh_dim)
470 oss << "umesh dimension mismatch : this mesh dimension=" << _mesh_dim << " other mesh dimension=" << otherC->_mesh_dim;
474 if(_types!=otherC->_types)
476 oss << "umesh geometric type mismatch :\nThis geometric types are :";
477 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
478 { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
479 oss << "\nOther geometric types are :";
480 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=otherC->_types.begin();iter!=otherC->_types.end();iter++)
481 { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
485 if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
486 if(_nodal_connec==0 || otherC->_nodal_connec==0)
488 reason="Only one UMesh between the two this and other has its nodal connectivity DataArrayInt defined !";
491 if(_nodal_connec!=otherC->_nodal_connec)
492 if(!_nodal_connec->isEqualIfNotWhy(*otherC->_nodal_connec,reason))
494 reason.insert(0,"Nodal connectivity DataArrayInt differ : ");
497 if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
498 if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
500 reason="Only one UMesh between the two this and other has its nodal connectivity index DataArrayInt defined !";
503 if(_nodal_connec_index!=otherC->_nodal_connec_index)
504 if(!_nodal_connec_index->isEqualIfNotWhy(*otherC->_nodal_connec_index,reason))
506 reason.insert(0,"Nodal connectivity index DataArrayInt differ : ");
513 * Checks if data arrays of this mesh (node coordinates, nodal
514 * connectivity of cells, etc) of two meshes are same. Textual data like name etc. are
516 * \param [in] other - the mesh to compare with.
517 * \param [in] prec - precision value used to compare node coordinates.
518 * \return bool - \a true if the two meshes are same.
520 bool MEDCouplingUMesh::isEqualWithoutConsideringStr(const MEDCouplingMesh *other, double prec) const
522 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
525 if(!MEDCouplingPointSet::isEqualWithoutConsideringStr(other,prec))
527 if(_mesh_dim!=otherC->_mesh_dim)
529 if(_types!=otherC->_types)
531 if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
532 if(_nodal_connec==0 || otherC->_nodal_connec==0)
534 if(_nodal_connec!=otherC->_nodal_connec)
535 if(!_nodal_connec->isEqualWithoutConsideringStr(*otherC->_nodal_connec))
537 if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
538 if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
540 if(_nodal_connec_index!=otherC->_nodal_connec_index)
541 if(!_nodal_connec_index->isEqualWithoutConsideringStr(*otherC->_nodal_connec_index))
547 * Checks if \a this and \a other meshes are geometrically equivalent with high
548 * probability, else an exception is thrown. The meshes are considered equivalent if
549 * (1) meshes contain the same number of nodes and the same number of elements of the
550 * same types (2) three cells of the two meshes (first, last and middle) are based
551 * on coincident nodes (with a specified precision).
552 * \param [in] other - the mesh to compare with.
553 * \param [in] prec - the precision used to compare nodes of the two meshes.
554 * \throw If the two meshes do not match.
556 void MEDCouplingUMesh::checkFastEquivalWith(const MEDCouplingMesh *other, double prec) const
558 MEDCouplingPointSet::checkFastEquivalWith(other,prec);
559 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
561 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkFastEquivalWith : Two meshes are not not unstructured !");
565 * Returns the reverse nodal connectivity. The reverse nodal connectivity enumerates
566 * cells each node belongs to.
567 * \warning For speed reasons, this method does not check if node ids in the nodal
568 * connectivity correspond to the size of node coordinates array.
569 * \param [in,out] revNodal - an array holding ids of cells sharing each node.
570 * \param [in,out] revNodalIndx - an array, of length \a this->getNumberOfNodes() + 1,
571 * dividing cell ids in \a revNodal into groups each referring to one
572 * node. Its every element (except the last one) is an index pointing to the
573 * first id of a group of cells. For example cells sharing the node #1 are
574 * described by following range of indices:
575 * [ \a revNodalIndx[1], \a revNodalIndx[2] ) and the cell ids are
576 * \a revNodal[ \a revNodalIndx[1] ], \a revNodal[ \a revNodalIndx[1] + 1], ...
577 * Number of cells sharing the *i*-th node is
578 * \a revNodalIndx[ *i*+1 ] - \a revNodalIndx[ *i* ].
579 * \throw If the coordinates array is not set.
580 * \throw If the nodal connectivity of cells is not defined.
582 * \if ENABLE_EXAMPLES
583 * \ref cpp_mcumesh_getReverseNodalConnectivity "Here is a C++ example".<br>
584 * \ref py_mcumesh_getReverseNodalConnectivity "Here is a Python example".
587 void MEDCouplingUMesh::getReverseNodalConnectivity(DataArrayInt *revNodal, DataArrayInt *revNodalIndx) const
590 int nbOfNodes=getNumberOfNodes();
591 int *revNodalIndxPtr=(int *)malloc((nbOfNodes+1)*sizeof(int));
592 revNodalIndx->useArray(revNodalIndxPtr,true,C_DEALLOC,nbOfNodes+1,1);
593 std::fill(revNodalIndxPtr,revNodalIndxPtr+nbOfNodes+1,0);
594 const int *conn=_nodal_connec->getConstPointer();
595 const int *connIndex=_nodal_connec_index->getConstPointer();
596 int nbOfCells=getNumberOfCells();
597 int nbOfEltsInRevNodal=0;
598 for(int eltId=0;eltId<nbOfCells;eltId++)
600 const int *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
601 const int *endNdlConnOfCurCell=conn+connIndex[eltId+1];
602 for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
603 if(*iter>=0)//for polyhedrons
605 nbOfEltsInRevNodal++;
606 revNodalIndxPtr[(*iter)+1]++;
609 std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<int>());
610 int *revNodalPtr=(int *)malloc((nbOfEltsInRevNodal)*sizeof(int));
611 revNodal->useArray(revNodalPtr,true,C_DEALLOC,nbOfEltsInRevNodal,1);
612 std::fill(revNodalPtr,revNodalPtr+nbOfEltsInRevNodal,-1);
613 for(int eltId=0;eltId<nbOfCells;eltId++)
615 const int *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
616 const int *endNdlConnOfCurCell=conn+connIndex[eltId+1];
617 for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
618 if(*iter>=0)//for polyhedrons
619 *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind2nd(std::equal_to<int>(),-1))=eltId;
625 int MEDCouplingFastNbrer(int id, unsigned nb, const INTERP_KERNEL::CellModel& cm, bool compute, const int *conn1, const int *conn2)
630 int MEDCouplingOrientationSensitiveNbrer(int id, unsigned nb, const INTERP_KERNEL::CellModel& cm, bool compute, const int *conn1, const int *conn2)
636 if(cm.getOrientationStatus(nb,conn1,conn2))
643 class MinusOneSonsGenerator
646 MinusOneSonsGenerator(const INTERP_KERNEL::CellModel& cm):_cm(cm) { }
647 unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfSons2(conn,lgth); }
648 unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillSonCellNodalConnectivity2(sonId,nodalConn,lgth,sonNodalConn,typeOfSon); }
649 static const int DELTA=1;
651 const INTERP_KERNEL::CellModel& _cm;
654 class MinusOneSonsGeneratorBiQuadratic
657 MinusOneSonsGeneratorBiQuadratic(const INTERP_KERNEL::CellModel& cm):_cm(cm) { }
658 unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfSons2(conn,lgth); }
659 unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillSonCellNodalConnectivity4(sonId,nodalConn,lgth,sonNodalConn,typeOfSon); }
660 static const int DELTA=1;
662 const INTERP_KERNEL::CellModel& _cm;
665 class MinusTwoSonsGenerator
668 MinusTwoSonsGenerator(const INTERP_KERNEL::CellModel& cm):_cm(cm) { }
669 unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfEdgesIn3D(conn,lgth); }
670 unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillSonEdgesNodalConnectivity3D(sonId,nodalConn,lgth,sonNodalConn,typeOfSon); }
671 static const int DELTA=2;
673 const INTERP_KERNEL::CellModel& _cm;
679 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
680 * this->getMeshDimension(), that bound cells of \a this mesh. In addition arrays
681 * describing correspondence between cells of \a this and the result meshes are
682 * returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending connectivity,
683 * i.e. enumerate cells of the result mesh bounding each cell of \a this mesh. The
684 * arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
685 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
686 * \warning For speed reasons, this method does not check if node ids in the nodal
687 * connectivity correspond to the size of node coordinates array.
688 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
689 * to write this mesh to the MED file, its cells must be sorted using
690 * sortCellsInMEDFileFrmt().
691 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
692 * each cell of \a this mesh.
693 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
694 * dividing cell ids in \a desc into groups each referring to one
695 * cell of \a this mesh. Its every element (except the last one) is an index
696 * pointing to the first id of a group of cells. For example cells of the
697 * result mesh bounding the cell #1 of \a this mesh are described by following
699 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
700 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
701 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
702 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
703 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
704 * by each cell of the result mesh.
705 * \param [in,out] revDescIndx - the array, of length one more than number of cells
706 * in the result mesh,
707 * dividing cell ids in \a revDesc into groups each referring to one
708 * cell of the result mesh the same way as \a descIndx divides \a desc.
709 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
710 * delete this mesh using decrRef() as it is no more needed.
711 * \throw If the coordinates array is not set.
712 * \throw If the nodal connectivity of cells is node defined.
713 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
714 * revDescIndx == NULL.
716 * \if ENABLE_EXAMPLES
717 * \ref cpp_mcumesh_buildDescendingConnectivity "Here is a C++ example".<br>
718 * \ref py_mcumesh_buildDescendingConnectivity "Here is a Python example".
720 * \sa buildDescendingConnectivity2()
722 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
724 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
728 * \a this has to have a mesh dimension equal to 3. If it is not the case an INTERP_KERNEL::Exception will be thrown.
729 * This behaves exactly as MEDCouplingUMesh::buildDescendingConnectivity does except that this method compute directly the transition from mesh dimension 3 to sub edges (dimension 1)
730 * in one shot. That is to say that this method is equivalent to 2 successive calls to MEDCouplingUMesh::buildDescendingConnectivity.
731 * This method returns 4 arrays and a mesh as MEDCouplingUMesh::buildDescendingConnectivity does.
732 * \sa MEDCouplingUMesh::buildDescendingConnectivity
734 MEDCouplingUMesh *MEDCouplingUMesh::explode3DMeshTo1D(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
737 if(getMeshDimension()!=3)
738 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explode3DMeshTo1D : This has to have a mesh dimension to 3 !");
739 return buildDescendingConnectivityGen<MinusTwoSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
743 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
744 * this->getMeshDimension(), that bound cells of \a this mesh. In
745 * addition arrays describing correspondence between cells of \a this and the result
746 * meshes are returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending
747 * connectivity, i.e. enumerate cells of the result mesh bounding each cell of \a this
748 * mesh. This method differs from buildDescendingConnectivity() in that apart
749 * from cell ids, \a desc returns mutual orientation of cells in \a this and the
750 * result meshes. So a positive id means that order of nodes in corresponding cells
751 * of two meshes is same, and a negative id means a reverse order of nodes. Since a
752 * cell with id #0 can't be negative, the array \a desc returns ids in FORTRAN mode,
753 * i.e. cell ids are one-based.
754 * Arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
755 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
756 * \warning For speed reasons, this method does not check if node ids in the nodal
757 * connectivity correspond to the size of node coordinates array.
758 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
759 * to write this mesh to the MED file, its cells must be sorted using
760 * sortCellsInMEDFileFrmt().
761 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
762 * each cell of \a this mesh.
763 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
764 * dividing cell ids in \a desc into groups each referring to one
765 * cell of \a this mesh. Its every element (except the last one) is an index
766 * pointing to the first id of a group of cells. For example cells of the
767 * result mesh bounding the cell #1 of \a this mesh are described by following
769 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
770 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
771 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
772 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
773 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
774 * by each cell of the result mesh.
775 * \param [in,out] revDescIndx - the array, of length one more than number of cells
776 * in the result mesh,
777 * dividing cell ids in \a revDesc into groups each referring to one
778 * cell of the result mesh the same way as \a descIndx divides \a desc.
779 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This result mesh
780 * shares the node coordinates array with \a this mesh. The caller is to
781 * delete this mesh using decrRef() as it is no more needed.
782 * \throw If the coordinates array is not set.
783 * \throw If the nodal connectivity of cells is node defined.
784 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
785 * revDescIndx == NULL.
787 * \if ENABLE_EXAMPLES
788 * \ref cpp_mcumesh_buildDescendingConnectivity2 "Here is a C++ example".<br>
789 * \ref py_mcumesh_buildDescendingConnectivity2 "Here is a Python example".
791 * \sa buildDescendingConnectivity()
793 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
795 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingOrientationSensitiveNbrer);
799 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
800 * For speed reasons no check of this will be done. This method calls
801 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
802 * This method lists cell by cell in \b this which are its neighbors. To compute the result
803 * only connectivities are considered.
804 * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
805 * The format of return is hence \ref numbering-indirect.
807 * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly
808 * allocated and should be dealt by the caller. \b neighborsIndx 2nd output
809 * parameter allows to select the right part in this array (\ref numbering-indirect). The number of tuples
810 * is equal to the last values in \b neighborsIndx.
811 * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be
812 * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
814 void MEDCouplingUMesh::computeNeighborsOfCells(DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx) const
816 MCAuto<DataArrayInt> desc=DataArrayInt::New();
817 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
818 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
819 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
820 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
822 ComputeNeighborsOfCellsAdv(desc,descIndx,revDesc,revDescIndx,neighbors,neighborsIndx);
826 * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm
827 * of MEDCouplingUMesh::computeNeighborsOfCells.
828 * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is
829 * typically the case to extract a set a neighbours,
830 * excluding a set of meshdim-1 cells in input descending connectivity.
831 * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx (\ref numbering-indirect) input params are
832 * the result of MEDCouplingUMesh::buildDescendingConnectivity.
833 * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities
835 * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
837 * \param [in] desc descending connectivity array.
838 * \param [in] descIndx descending connectivity index array used to walk through \b desc (\ref numbering-indirect).
839 * \param [in] revDesc reverse descending connectivity array.
840 * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc (\ref numbering-indirect).
841 * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
842 * parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
843 * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
845 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayInt *desc, const DataArrayInt *descIndx, const DataArrayInt *revDesc, const DataArrayInt *revDescIndx,
846 DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx)
848 if(!desc || !descIndx || !revDesc || !revDescIndx)
849 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
850 const int *descPtr=desc->getConstPointer();
851 const int *descIPtr=descIndx->getConstPointer();
852 const int *revDescPtr=revDesc->getConstPointer();
853 const int *revDescIPtr=revDescIndx->getConstPointer();
855 int nbCells=descIndx->getNumberOfTuples()-1;
856 MCAuto<DataArrayInt> out0=DataArrayInt::New();
857 MCAuto<DataArrayInt> out1=DataArrayInt::New(); out1->alloc(nbCells+1,1);
858 int *out1Ptr=out1->getPointer();
860 out0->reserve(desc->getNumberOfTuples());
861 for(int i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
863 for(const int *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
865 std::set<int> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
867 out0->insertAtTheEnd(s.begin(),s.end());
869 *out1Ptr=out0->getNumberOfTuples();
871 neighbors=out0.retn();
872 neighborsIndx=out1.retn();
876 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
877 * For speed reasons no check of this will be done. This method calls
878 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
879 * This method lists node by node in \b this which are its neighbors. To compute the result
880 * only connectivities are considered.
881 * The neighbor nodes of node having id 'nodeId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
883 * \param [out] neighbors is an array storing all the neighbors of all nodes in \b this. This array
884 * is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
885 * parameter allows to select the right part in this array (\ref numbering-indirect).
886 * The number of tuples is equal to the last values in \b neighborsIndx.
887 * \param [out] neighborsIdx is an array of size this->getNumberOfCells()+1 newly allocated and should
888 * be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
890 void MEDCouplingUMesh::computeNeighborsOfNodes(DataArrayInt *&neighbors, DataArrayInt *&neighborsIdx) const
893 int mdim(getMeshDimension()),nbNodes(getNumberOfNodes());
894 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descIndx(DataArrayInt::New()),revDesc(DataArrayInt::New()),revDescIndx(DataArrayInt::New());
895 MCAuto<MEDCouplingUMesh> mesh1D;
900 mesh1D=explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx);
905 mesh1D=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
910 mesh1D=const_cast<MEDCouplingUMesh *>(this);
916 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2,1] !");
919 desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=0; revDescIndx=0;
920 mesh1D->getReverseNodalConnectivity(desc,descIndx);
921 MCAuto<DataArrayInt> ret0(DataArrayInt::New());
922 ret0->alloc(desc->getNumberOfTuples(),1);
923 int *r0Pt(ret0->getPointer());
924 const int *c1DPtr(mesh1D->getNodalConnectivity()->begin()),*rn(desc->begin()),*rni(descIndx->begin());
925 for(int i=0;i<nbNodes;i++,rni++)
927 for(const int *oneDCellIt=rn+rni[0];oneDCellIt!=rn+rni[1];oneDCellIt++)
928 *r0Pt++=c1DPtr[3*(*oneDCellIt)+1]==i?c1DPtr[3*(*oneDCellIt)+2]:c1DPtr[3*(*oneDCellIt)+1];
930 neighbors=ret0.retn();
931 neighborsIdx=descIndx.retn();
937 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
938 * For speed reasons no check of this will be done.
940 template<class SonsGenerator>
941 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivityGen(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx, DimM1DescNbrer nbrer) const
943 if(!desc || !descIndx || !revDesc || !revDescIndx)
944 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildDescendingConnectivityGen : present of a null pointer in input !");
945 checkConnectivityFullyDefined();
946 int nbOfCells=getNumberOfCells();
947 int nbOfNodes=getNumberOfNodes();
948 MCAuto<DataArrayInt> revNodalIndx=DataArrayInt::New(); revNodalIndx->alloc(nbOfNodes+1,1); revNodalIndx->fillWithZero();
949 int *revNodalIndxPtr=revNodalIndx->getPointer();
950 const int *conn=_nodal_connec->getConstPointer();
951 const int *connIndex=_nodal_connec_index->getConstPointer();
952 std::string name="Mesh constituent of "; name+=getName();
953 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(name,getMeshDimension()-SonsGenerator::DELTA);
954 ret->setCoords(getCoords());
955 ret->allocateCells(2*nbOfCells);
956 descIndx->alloc(nbOfCells+1,1);
957 MCAuto<DataArrayInt> revDesc2(DataArrayInt::New()); revDesc2->reserve(2*nbOfCells);
958 int *descIndxPtr=descIndx->getPointer(); *descIndxPtr++=0;
959 for(int eltId=0;eltId<nbOfCells;eltId++,descIndxPtr++)
961 int pos=connIndex[eltId];
962 int posP1=connIndex[eltId+1];
963 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[pos]);
964 SonsGenerator sg(cm);
965 unsigned nbOfSons=sg.getNumberOfSons2(conn+pos+1,posP1-pos-1);
966 INTERP_KERNEL::AutoPtr<int> tmp=new int[posP1-pos];
967 for(unsigned i=0;i<nbOfSons;i++)
969 INTERP_KERNEL::NormalizedCellType cmsId;
970 unsigned nbOfNodesSon=sg.fillSonCellNodalConnectivity2(i,conn+pos+1,posP1-pos-1,tmp,cmsId);
971 for(unsigned k=0;k<nbOfNodesSon;k++)
973 revNodalIndxPtr[tmp[k]+1]++;
974 ret->insertNextCell(cmsId,nbOfNodesSon,tmp);
975 revDesc2->pushBackSilent(eltId);
977 descIndxPtr[0]=descIndxPtr[-1]+(int)nbOfSons;
979 int nbOfCellsM1=ret->getNumberOfCells();
980 std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<int>());
981 MCAuto<DataArrayInt> revNodal=DataArrayInt::New(); revNodal->alloc(revNodalIndx->back(),1);
982 std::fill(revNodal->getPointer(),revNodal->getPointer()+revNodalIndx->back(),-1);
983 int *revNodalPtr=revNodal->getPointer();
984 const int *connM1=ret->getNodalConnectivity()->getConstPointer();
985 const int *connIndexM1=ret->getNodalConnectivityIndex()->getConstPointer();
986 for(int eltId=0;eltId<nbOfCellsM1;eltId++)
988 const int *strtNdlConnOfCurCell=connM1+connIndexM1[eltId]+1;
989 const int *endNdlConnOfCurCell=connM1+connIndexM1[eltId+1];
990 for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
991 if(*iter>=0)//for polyhedrons
992 *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind2nd(std::equal_to<int>(),-1))=eltId;
995 DataArrayInt *commonCells=0,*commonCellsI=0;
996 FindCommonCellsAlg(3,0,ret->getNodalConnectivity(),ret->getNodalConnectivityIndex(),revNodal,revNodalIndx,commonCells,commonCellsI);
997 MCAuto<DataArrayInt> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
998 const int *commonCellsPtr(commonCells->getConstPointer()),*commonCellsIPtr(commonCellsI->getConstPointer());
999 int newNbOfCellsM1=-1;
1000 MCAuto<DataArrayInt> o2nM1=DataArrayInt::ConvertIndexArrayToO2N(nbOfCellsM1,commonCells->begin(),
1001 commonCellsI->begin(),commonCellsI->end(),newNbOfCellsM1);
1002 std::vector<bool> isImpacted(nbOfCellsM1,false);
1003 for(const int *work=commonCellsI->begin();work!=commonCellsI->end()-1;work++)
1004 for(int work2=work[0];work2!=work[1];work2++)
1005 isImpacted[commonCellsPtr[work2]]=true;
1006 const int *o2nM1Ptr=o2nM1->getConstPointer();
1007 MCAuto<DataArrayInt> n2oM1=o2nM1->invertArrayO2N2N2OBis(newNbOfCellsM1);
1008 const int *n2oM1Ptr=n2oM1->getConstPointer();
1009 MCAuto<MEDCouplingUMesh> ret2=static_cast<MEDCouplingUMesh *>(ret->buildPartOfMySelf(n2oM1->begin(),n2oM1->end(),true));
1010 ret2->copyTinyInfoFrom(this);
1011 desc->alloc(descIndx->back(),1);
1012 int *descPtr=desc->getPointer();
1013 const INTERP_KERNEL::CellModel& cmsDft=INTERP_KERNEL::CellModel::GetCellModel(INTERP_KERNEL::NORM_POINT1);
1014 for(int i=0;i<nbOfCellsM1;i++,descPtr++)
1017 *descPtr=nbrer(o2nM1Ptr[i],0,cmsDft,false,0,0);
1020 if(i!=n2oM1Ptr[o2nM1Ptr[i]])
1022 const INTERP_KERNEL::CellModel& cms=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connM1[connIndexM1[i]]);
1023 *descPtr=nbrer(o2nM1Ptr[i],connIndexM1[i+1]-connIndexM1[i]-1,cms,true,connM1+connIndexM1[n2oM1Ptr[o2nM1Ptr[i]]]+1,connM1+connIndexM1[i]+1);
1026 *descPtr=nbrer(o2nM1Ptr[i],0,cmsDft,false,0,0);
1029 revDesc->reserve(newNbOfCellsM1);
1030 revDescIndx->alloc(newNbOfCellsM1+1,1);
1031 int *revDescIndxPtr=revDescIndx->getPointer(); *revDescIndxPtr++=0;
1032 const int *revDesc2Ptr=revDesc2->getConstPointer();
1033 for(int i=0;i<newNbOfCellsM1;i++,revDescIndxPtr++)
1035 int oldCellIdM1=n2oM1Ptr[i];
1036 if(!isImpacted[oldCellIdM1])
1038 revDesc->pushBackSilent(revDesc2Ptr[oldCellIdM1]);
1039 revDescIndxPtr[0]=revDescIndxPtr[-1]+1;
1043 for(int j=commonCellsIPtr[0];j<commonCellsIPtr[1];j++)
1044 revDesc->pushBackSilent(revDesc2Ptr[commonCellsPtr[j]]);
1045 revDescIndxPtr[0]=revDescIndxPtr[-1]+commonCellsIPtr[1]-commonCellsIPtr[0];
1053 struct MEDCouplingAccVisit
1055 MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1056 int operator()(int val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1057 int _new_nb_of_nodes;
1063 * Converts specified cells to either polygons (if \a this is a 2D mesh) or
1064 * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an
1065 * array of cell ids. Pay attention that after conversion all algorithms work slower
1066 * with \a this mesh than before conversion. <br> If an exception is thrown during the
1067 * conversion due presence of invalid ids in the array of cells to convert, as a
1068 * result \a this mesh contains some already converted elements. In this case the 2D
1069 * mesh remains valid but 3D mesh becomes \b inconsistent!
1070 * \warning This method can significantly modify the order of geometric types in \a this,
1071 * hence, to write this mesh to the MED file, its cells must be sorted using
1072 * sortCellsInMEDFileFrmt().
1073 * \param [in] cellIdsToConvertBg - the array holding ids of cells to convert.
1074 * \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a
1075 * cellIdsToConvertBg.
1076 * \throw If the coordinates array is not set.
1077 * \throw If the nodal connectivity of cells is node defined.
1078 * \throw If dimension of \a this mesh is not either 2 or 3.
1080 * \if ENABLE_EXAMPLES
1081 * \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".<br>
1082 * \ref py_mcumesh_convertToPolyTypes "Here is a Python example".
1085 void MEDCouplingUMesh::convertToPolyTypes(const int *cellIdsToConvertBg, const int *cellIdsToConvertEnd)
1087 checkFullyDefined();
1088 int dim=getMeshDimension();
1090 throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
1091 int nbOfCells(getNumberOfCells());
1094 const int *connIndex=_nodal_connec_index->getConstPointer();
1095 int *conn=_nodal_connec->getPointer();
1096 for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1098 if(*iter>=0 && *iter<nbOfCells)
1100 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
1101 if(!cm.isQuadratic())
1102 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
1104 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
1108 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1109 oss << " in range [0," << nbOfCells << ") !";
1110 throw INTERP_KERNEL::Exception(oss.str().c_str());
1116 int *connIndex(_nodal_connec_index->getPointer());
1117 const int *connOld(_nodal_connec->getConstPointer());
1118 MCAuto<DataArrayInt> connNew(DataArrayInt::New()),connNewI(DataArrayInt::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0);
1119 std::vector<bool> toBeDone(nbOfCells,false);
1120 for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1122 if(*iter>=0 && *iter<nbOfCells)
1123 toBeDone[*iter]=true;
1126 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1127 oss << " in range [0," << nbOfCells << ") !";
1128 throw INTERP_KERNEL::Exception(oss.str().c_str());
1131 for(int cellId=0;cellId<nbOfCells;cellId++)
1133 int pos(connIndex[cellId]),posP1(connIndex[cellId+1]);
1134 int lgthOld(posP1-pos-1);
1135 if(toBeDone[cellId])
1137 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connOld[pos]);
1138 unsigned nbOfFaces(cm.getNumberOfSons2(connOld+pos+1,lgthOld));
1139 int *tmp(new int[nbOfFaces*lgthOld+1]);
1140 int *work=tmp; *work++=INTERP_KERNEL::NORM_POLYHED;
1141 for(unsigned j=0;j<nbOfFaces;j++)
1143 INTERP_KERNEL::NormalizedCellType type;
1144 unsigned offset=cm.fillSonCellNodalConnectivity2(j,connOld+pos+1,lgthOld,work,type);
1148 std::size_t newLgth(std::distance(tmp,work)-1);//-1 for last -1
1149 connNew->pushBackValsSilent(tmp,tmp+newLgth);
1150 connNewI->pushBackSilent(connNewI->back()+(int)newLgth);
1155 connNew->pushBackValsSilent(connOld+pos,connOld+posP1);
1156 connNewI->pushBackSilent(connNewI->back()+posP1-pos);
1159 setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind.
1165 * Converts all cells to either polygons (if \a this is a 2D mesh) or
1166 * polyhedrons (if \a this is a 3D mesh).
1167 * \warning As this method is purely for user-friendliness and no optimization is
1168 * done to avoid construction of a useless vector, this method can be costly
1170 * \throw If the coordinates array is not set.
1171 * \throw If the nodal connectivity of cells is node defined.
1172 * \throw If dimension of \a this mesh is not either 2 or 3.
1174 void MEDCouplingUMesh::convertAllToPoly()
1176 int nbOfCells=getNumberOfCells();
1177 std::vector<int> cellIds(nbOfCells);
1178 for(int i=0;i<nbOfCells;i++)
1180 convertToPolyTypes(&cellIds[0],&cellIds[0]+cellIds.size());
1184 * Fixes nodal connectivity of invalid cells of type NORM_POLYHED. This method
1185 * expects that all NORM_POLYHED cells have connectivity similar to that of prismatic
1186 * volumes like NORM_HEXA8, NORM_PENTA6 etc., i.e. the first half of nodes describes a
1187 * base facet of the volume and the second half of nodes describes an opposite facet
1188 * having the same number of nodes as the base one. This method converts such
1189 * connectivity to a valid polyhedral format where connectivity of each facet is
1190 * explicitly described and connectivity of facets are separated by -1. If \a this mesh
1191 * contains a NORM_POLYHED cell with a valid connectivity, or an invalid connectivity is
1192 * not as expected, an exception is thrown and the mesh remains unchanged. Care of
1193 * a correct orientation of the first facet of a polyhedron, else orientation of a
1194 * corrected cell is reverse.<br>
1195 * This method is useful to build an extruded unstructured mesh with polyhedrons as
1196 * it releases the user from boring description of polyhedra connectivity in the valid
1198 * \throw If \a this->getMeshDimension() != 3.
1199 * \throw If \a this->getSpaceDimension() != 3.
1200 * \throw If the nodal connectivity of cells is not defined.
1201 * \throw If the coordinates array is not set.
1202 * \throw If \a this mesh contains polyhedrons with the valid connectivity.
1203 * \throw If \a this mesh contains polyhedrons with odd number of nodes.
1205 * \if ENABLE_EXAMPLES
1206 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
1207 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
1210 void MEDCouplingUMesh::convertExtrudedPolyhedra()
1212 checkFullyDefined();
1213 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1214 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
1215 int nbOfCells=getNumberOfCells();
1216 MCAuto<DataArrayInt> newCi=DataArrayInt::New();
1217 newCi->alloc(nbOfCells+1,1);
1218 int *newci=newCi->getPointer();
1219 const int *ci=_nodal_connec_index->getConstPointer();
1220 const int *c=_nodal_connec->getConstPointer();
1222 for(int i=0;i<nbOfCells;i++)
1224 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1225 if(type==INTERP_KERNEL::NORM_POLYHED)
1227 if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
1229 std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
1230 throw INTERP_KERNEL::Exception(oss.str().c_str());
1232 std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
1235 std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron with 1 face but there is a mismatch of number of nodes in face should be even !";
1236 throw INTERP_KERNEL::Exception(oss.str().c_str());
1239 newci[i+1]=7*n1+2+newci[i];//6*n1 (nodal length) + n1+2 (number of faces) - 1 (number of '-1' separator is equal to number of faces -1) + 1 (for cell type)
1242 newci[i+1]=(ci[i+1]-ci[i])+newci[i];
1244 MCAuto<DataArrayInt> newC=DataArrayInt::New();
1245 newC->alloc(newci[nbOfCells],1);
1246 int *newc=newC->getPointer();
1247 for(int i=0;i<nbOfCells;i++)
1249 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1250 if(type==INTERP_KERNEL::NORM_POLYHED)
1252 std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
1253 newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
1255 for(std::size_t j=0;j<n1;j++)
1257 newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
1259 newc[n1+5*j+1]=c[ci[i]+1+j];
1260 newc[n1+5*j+2]=c[ci[i]+1+j+n1];
1261 newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
1262 newc[n1+5*j+4]=c[ci[i]+1+(j+1)%n1];
1267 newc=std::copy(c+ci[i],c+ci[i+1],newc);
1269 _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
1270 _nodal_connec->decrRef(); _nodal_connec=newC.retn();
1275 * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D
1276 * mesh) to cells of classical types. This method is opposite to convertToPolyTypes().
1277 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
1278 * to write this mesh to the MED file, its cells must be sorted using
1279 * sortCellsInMEDFileFrmt().
1280 * \return \c true if at least one cell has been converted, \c false else. In the
1281 * last case the nodal connectivity remains unchanged.
1282 * \throw If the coordinates array is not set.
1283 * \throw If the nodal connectivity of cells is not defined.
1284 * \throw If \a this->getMeshDimension() < 0.
1286 bool MEDCouplingUMesh::unPolyze()
1288 checkFullyDefined();
1289 int mdim=getMeshDimension();
1291 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1294 int nbOfCells=getNumberOfCells();
1297 int initMeshLgth=getNodalConnectivityArrayLen();
1298 int *conn=_nodal_connec->getPointer();
1299 int *index=_nodal_connec_index->getPointer();
1304 for(int i=0;i<nbOfCells;i++)
1306 lgthOfCurCell=index[i+1]-posOfCurCell;
1307 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1308 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1309 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1313 switch(cm.getDimension())
1317 INTERP_KERNEL::AutoPtr<int> tmp=new int[lgthOfCurCell-1];
1318 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(int *)tmp);
1319 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1324 int nbOfFaces,lgthOfPolyhConn;
1325 INTERP_KERNEL::AutoPtr<int> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1326 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1331 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1335 ret=ret || (newType!=type);
1336 conn[newPos]=newType;
1338 posOfCurCell=index[i+1];
1343 std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1344 newPos+=lgthOfCurCell;
1345 posOfCurCell+=lgthOfCurCell;
1349 if(newPos!=initMeshLgth)
1350 _nodal_connec->reAlloc(newPos);
1357 * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1358 * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1359 * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells.
1361 * \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
1364 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1366 checkFullyDefined();
1367 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1368 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1369 MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1370 coords->recenterForMaxPrecision(eps);
1372 int nbOfCells=getNumberOfCells();
1373 const int *conn=_nodal_connec->getConstPointer();
1374 const int *index=_nodal_connec_index->getConstPointer();
1375 MCAuto<DataArrayInt> connINew=DataArrayInt::New();
1376 connINew->alloc(nbOfCells+1,1);
1377 int *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1378 MCAuto<DataArrayInt> connNew=DataArrayInt::New(); connNew->alloc(0,1);
1380 for(int i=0;i<nbOfCells;i++,connINewPtr++)
1382 if(conn[index[i]]==(int)INTERP_KERNEL::NORM_POLYHED)
1384 SimplifyPolyhedronCell(eps,coords,conn+index[i],conn+index[i+1],connNew);
1388 connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1389 *connINewPtr=connNew->getNumberOfTuples();
1392 setConnectivity(connNew,connINew,false);
1396 * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1397 * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1398 * the format of the returned DataArrayInt instance.
1400 * \return a newly allocated DataArrayInt sorted ascendingly of fetched node ids.
1401 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1403 DataArrayInt *MEDCouplingUMesh::computeFetchedNodeIds() const
1405 checkConnectivityFullyDefined();
1406 int nbOfCells=getNumberOfCells();
1407 const int *connIndex=_nodal_connec_index->getConstPointer();
1408 const int *conn=_nodal_connec->getConstPointer();
1409 const int *maxEltPt=std::max_element(_nodal_connec->begin(),_nodal_connec->end());
1410 int maxElt=maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1;
1411 std::vector<bool> retS(maxElt,false);
1412 for(int i=0;i<nbOfCells;i++)
1413 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1417 for(int i=0;i<maxElt;i++)
1420 DataArrayInt *ret=DataArrayInt::New();
1422 int *retPtr=ret->getPointer();
1423 for(int i=0;i<maxElt;i++)
1430 * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1431 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1433 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1435 int nbOfNodes((int)nodeIdsInUse.size()),nbOfCells(getNumberOfCells());
1436 const int *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1437 for(int i=0;i<nbOfCells;i++)
1438 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1441 if(conn[j]<nbOfNodes)
1442 nodeIdsInUse[conn[j]]=true;
1445 std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1446 throw INTERP_KERNEL::Exception(oss.str().c_str());
1452 * Finds nodes not used in any cell and returns an array giving a new id to every node
1453 * by excluding the unused nodes, for which the array holds -1. The result array is
1454 * a mapping in "Old to New" mode.
1455 * \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1456 * \return DataArrayInt * - a new instance of DataArrayInt. Its length is \a
1457 * this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1458 * if the node is unused or a new id else. The caller is to delete this
1459 * array using decrRef() as it is no more needed.
1460 * \throw If the coordinates array is not set.
1461 * \throw If the nodal connectivity of cells is not defined.
1462 * \throw If the nodal connectivity includes an invalid id.
1464 * \if ENABLE_EXAMPLES
1465 * \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1466 * \ref py_mcumesh_getNodeIdsInUse "Here is a Python example".
1468 * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1470 DataArrayInt *MEDCouplingUMesh::getNodeIdsInUse(int& nbrOfNodesInUse) const
1473 int nbOfNodes(getNumberOfNodes());
1474 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1475 ret->alloc(nbOfNodes,1);
1476 int *traducer=ret->getPointer();
1477 std::fill(traducer,traducer+nbOfNodes,-1);
1478 int nbOfCells=getNumberOfCells();
1479 const int *connIndex=_nodal_connec_index->getConstPointer();
1480 const int *conn=_nodal_connec->getConstPointer();
1481 for(int i=0;i<nbOfCells;i++)
1482 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1485 if(conn[j]<nbOfNodes)
1486 traducer[conn[j]]=1;
1489 std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1490 throw INTERP_KERNEL::Exception(oss.str().c_str());
1493 nbrOfNodesInUse=(int)std::count(traducer,traducer+nbOfNodes,1);
1494 std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1499 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1500 * For each cell in \b this the number of nodes constituting cell is computed.
1501 * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1502 * So for pohyhedrons some nodes can be counted several times in the returned result.
1504 * \return a newly allocated array
1505 * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1507 DataArrayInt *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1509 checkConnectivityFullyDefined();
1510 int nbOfCells=getNumberOfCells();
1511 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1512 ret->alloc(nbOfCells,1);
1513 int *retPtr=ret->getPointer();
1514 const int *conn=getNodalConnectivity()->getConstPointer();
1515 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1516 for(int i=0;i<nbOfCells;i++,retPtr++)
1518 if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1519 *retPtr=connI[i+1]-connI[i]-1;
1521 *retPtr=connI[i+1]-connI[i]-1-std::count(conn+connI[i]+1,conn+connI[i+1],-1);
1527 * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1528 * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1530 * \return DataArrayInt * - new object to be deallocated by the caller.
1531 * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1533 DataArrayInt *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1535 checkConnectivityFullyDefined();
1536 int nbOfCells=getNumberOfCells();
1537 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1538 ret->alloc(nbOfCells,1);
1539 int *retPtr=ret->getPointer();
1540 const int *conn=getNodalConnectivity()->getConstPointer();
1541 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1542 for(int i=0;i<nbOfCells;i++,retPtr++)
1544 std::set<int> s(conn+connI[i]+1,conn+connI[i+1]);
1545 if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1546 *retPtr=(int)s.size();
1550 *retPtr=(int)s.size();
1557 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1558 * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1560 * \return a newly allocated array
1562 DataArrayInt *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1564 checkConnectivityFullyDefined();
1565 int nbOfCells=getNumberOfCells();
1566 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1567 ret->alloc(nbOfCells,1);
1568 int *retPtr=ret->getPointer();
1569 const int *conn=getNodalConnectivity()->getConstPointer();
1570 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1571 for(int i=0;i<nbOfCells;i++,retPtr++,connI++)
1573 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1574 *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1580 * Removes unused nodes (the node coordinates array is shorten) and returns an array
1581 * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1582 * array mean that the corresponding old node is no more used.
1583 * \return DataArrayInt * - a new instance of DataArrayInt of length \a
1584 * this->getNumberOfNodes() before call of this method. The caller is to
1585 * delete this array using decrRef() as it is no more needed.
1586 * \throw If the coordinates array is not set.
1587 * \throw If the nodal connectivity of cells is not defined.
1588 * \throw If the nodal connectivity includes an invalid id.
1589 * \sa areAllNodesFetched
1591 * \if ENABLE_EXAMPLES
1592 * \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1593 * \ref py_mcumesh_zipCoordsTraducer "Here is a Python example".
1596 DataArrayInt *MEDCouplingUMesh::zipCoordsTraducer()
1598 return MEDCouplingPointSet::zipCoordsTraducer();
1602 * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1603 * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1605 int MEDCouplingUMesh::AreCellsEqual(const int *conn, const int *connI, int cell1, int cell2, int compType)
1610 return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1612 return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1614 return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1616 return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1618 return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1620 throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1624 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1626 int MEDCouplingUMesh::AreCellsEqualPolicy0(const int *conn, const int *connI, int cell1, int cell2)
1628 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1629 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1634 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1636 int MEDCouplingUMesh::AreCellsEqualPolicy1(const int *conn, const int *connI, int cell1, int cell2)
1638 int sz=connI[cell1+1]-connI[cell1];
1639 if(sz==connI[cell2+1]-connI[cell2])
1641 if(conn[connI[cell1]]==conn[connI[cell2]])
1643 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1644 unsigned dim=cm.getDimension();
1650 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1651 int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1652 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1653 work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1654 return work!=tmp+sz1?1:0;
1657 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1660 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1667 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1669 int MEDCouplingUMesh::AreCellsEqualPolicy2(const int *conn, const int *connI, int cell1, int cell2)
1671 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1673 if(conn[connI[cell1]]==conn[connI[cell2]])
1675 std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1676 std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1684 * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1686 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const int *conn, const int *connI, int cell1, int cell2)
1688 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1690 std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1691 std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1698 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1700 int MEDCouplingUMesh::AreCellsEqualPolicy7(const int *conn, const int *connI, int cell1, int cell2)
1702 int sz=connI[cell1+1]-connI[cell1];
1703 if(sz==connI[cell2+1]-connI[cell2])
1705 if(conn[connI[cell1]]==conn[connI[cell2]])
1707 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1708 unsigned dim=cm.getDimension();
1714 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1715 int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1716 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1717 work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1722 std::reverse_iterator<int *> it1((int *)tmp+sz1);
1723 std::reverse_iterator<int *> it2((int *)tmp);
1724 if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1730 return work!=tmp+sz1?1:0;
1733 {//case of SEG2 and SEG3
1734 if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1736 if(!cm.isQuadratic())
1738 std::reverse_iterator<const int *> it1(conn+connI[cell1+1]);
1739 std::reverse_iterator<const int *> it2(conn+connI[cell1]+1);
1740 if(std::equal(it1,it2,conn+connI[cell2]+1))
1746 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])
1753 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1760 * This method find in candidate pool defined by 'candidates' the cells equal following the polycy 'compType'.
1761 * If any true is returned and the results will be put at the end of 'result' output parameter. If not false is returned
1762 * and result remains unchanged.
1763 * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1764 * If in 'candidates' pool -1 value is considered as an empty value.
1765 * WARNING this method returns only ONE set of result !
1767 bool MEDCouplingUMesh::AreCellsEqualInPool(const std::vector<int>& candidates, int compType, const int *conn, const int *connI, DataArrayInt *result)
1769 if(candidates.size()<1)
1772 std::vector<int>::const_iterator iter=candidates.begin();
1773 int start=(*iter++);
1774 for(;iter!=candidates.end();iter++)
1776 int status=AreCellsEqual(conn,connI,start,*iter,compType);
1781 result->pushBackSilent(start);
1785 result->pushBackSilent(*iter);
1787 result->pushBackSilent(status==2?(*iter+1):-(*iter+1));
1794 * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified
1796 * This method keeps the coordiantes of \a this. This method is time consuming.
1798 * \param [in] compType input specifying the technique used to compare cells each other.
1799 * - 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.
1800 * - 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)
1801 * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1802 * - 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
1803 * can be used for users not sensitive to orientation of cell
1804 * \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.
1805 * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1806 * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1807 * \return the correspondance array old to new in a newly allocated array.
1810 void MEDCouplingUMesh::findCommonCells(int compType, int startCellId, DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr) const
1812 MCAuto<DataArrayInt> revNodal=DataArrayInt::New(),revNodalI=DataArrayInt::New();
1813 getReverseNodalConnectivity(revNodal,revNodalI);
1814 FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1817 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, int startCellId, const DataArrayInt *nodal, const DataArrayInt *nodalI, const DataArrayInt *revNodal, const DataArrayInt *revNodalI,
1818 DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr)
1820 MCAuto<DataArrayInt> commonCells=DataArrayInt::New(),commonCellsI=DataArrayInt::New(); commonCells->alloc(0,1);
1821 int nbOfCells=nodalI->getNumberOfTuples()-1;
1822 commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1823 const int *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1824 const int *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1825 std::vector<bool> isFetched(nbOfCells,false);
1828 for(int i=0;i<nbOfCells;i++)
1832 const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1833 std::vector<int> v,v2;
1834 if(connOfNode!=connPtr+connIPtr[i+1])
1836 const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1837 v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1840 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1844 const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1845 std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1846 v2.resize(std::distance(v2.begin(),it));
1850 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1852 int pos=commonCellsI->back();
1853 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1854 for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1855 isFetched[*it]=true;
1863 for(int i=startCellId;i<nbOfCells;i++)
1867 const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1868 std::vector<int> v,v2;
1869 if(connOfNode!=connPtr+connIPtr[i+1])
1871 v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1874 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1878 std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1879 v2.resize(std::distance(v2.begin(),it));
1883 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1885 int pos=commonCellsI->back();
1886 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1887 for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1888 isFetched[*it]=true;
1894 commonCellsArr=commonCells.retn();
1895 commonCellsIArr=commonCellsI.retn();
1899 * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1900 * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1901 * than \a other->getNumberOfCells() in the returned array means that there is no
1902 * corresponding cell in \a this mesh.
1903 * It is expected that \a this and \a other meshes share the same node coordinates
1904 * array, if it is not so an exception is thrown.
1905 * \param [in] other - the mesh to compare with.
1906 * \param [in] compType - specifies a cell comparison technique. For meaning of its
1907 * valid values [0,1,2], see zipConnectivityTraducer().
1908 * \param [out] arr - a new instance of DataArrayInt returning correspondence
1909 * between cells of the two meshes. It contains \a other->getNumberOfCells()
1910 * values. The caller is to delete this array using
1911 * decrRef() as it is no more needed.
1912 * \return bool - \c true if all cells of \a other mesh are present in the \a this
1915 * \if ENABLE_EXAMPLES
1916 * \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1917 * \ref py_mcumesh_areCellsIncludedIn "Here is a Python example".
1919 * \sa checkDeepEquivalOnSameNodesWith()
1920 * \sa checkGeoEquivalWith()
1922 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayInt *& arr) const
1924 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1925 int nbOfCells=getNumberOfCells();
1926 static const int possibleCompType[]={0,1,2};
1927 if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1929 std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1930 std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1932 throw INTERP_KERNEL::Exception(oss.str().c_str());
1934 MCAuto<DataArrayInt> o2n=mesh->zipConnectivityTraducer(compType,nbOfCells);
1935 arr=o2n->subArray(nbOfCells);
1936 arr->setName(other->getName());
1938 if(other->getNumberOfCells()==0)
1940 return arr->getMaxValue(tmp)<nbOfCells;
1944 * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1945 * This method tries to determine if \b other is fully included in \b this.
1946 * The main difference is that this method is not expected to throw exception.
1947 * This method has two outputs :
1949 * \param other other mesh
1950 * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1951 * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
1953 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayInt *& arr) const
1955 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1956 DataArrayInt *commonCells=0,*commonCellsI=0;
1957 int thisNbCells=getNumberOfCells();
1958 mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
1959 MCAuto<DataArrayInt> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1960 const int *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
1961 int otherNbCells=other->getNumberOfCells();
1962 MCAuto<DataArrayInt> arr2=DataArrayInt::New();
1963 arr2->alloc(otherNbCells,1);
1964 arr2->fillWithZero();
1965 int *arr2Ptr=arr2->getPointer();
1966 int nbOfCommon=commonCellsI->getNumberOfTuples()-1;
1967 for(int i=0;i<nbOfCommon;i++)
1969 int start=commonCellsPtr[commonCellsIPtr[i]];
1970 if(start<thisNbCells)
1972 for(int j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
1974 int sig=commonCellsPtr[j]>0?1:-1;
1975 int val=std::abs(commonCellsPtr[j])-1;
1976 if(val>=thisNbCells)
1977 arr2Ptr[val-thisNbCells]=sig*(start+1);
1981 arr2->setName(other->getName());
1982 if(arr2->presenceOfValue(0))
1988 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
1991 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
1992 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
1994 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
1995 std::vector<const MEDCouplingUMesh *> ms(2);
1998 return MergeUMeshesOnSameCoords(ms);
2002 * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
2003 * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
2004 * cellIds is not given explicitely but by a range python like.
2009 * \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.
2010 * \return a newly allocated
2012 * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
2013 * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
2015 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(int start, int end, int step, bool keepCoords) const
2017 if(getMeshDimension()!=-1)
2018 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
2021 int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
2023 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2025 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2027 return const_cast<MEDCouplingUMesh *>(this);
2032 * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
2033 * The result mesh shares or not the node coordinates array with \a this mesh depending
2034 * on \a keepCoords parameter.
2035 * \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
2036 * to write this mesh to the MED file, its cells must be sorted using
2037 * sortCellsInMEDFileFrmt().
2038 * \param [in] begin - an array of cell ids to include to the new mesh.
2039 * \param [in] end - a pointer to last-plus-one-th element of \a begin.
2040 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2041 * array of \a this mesh, else "free" nodes are removed from the result mesh
2042 * by calling zipCoords().
2043 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2044 * to delete this mesh using decrRef() as it is no more needed.
2045 * \throw If the coordinates array is not set.
2046 * \throw If the nodal connectivity of cells is not defined.
2047 * \throw If any cell id in the array \a begin is not valid.
2049 * \if ENABLE_EXAMPLES
2050 * \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
2051 * \ref py_mcumesh_buildPartOfMySelf "Here is a Python example".
2054 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const int *begin, const int *end, bool keepCoords) const
2056 if(getMeshDimension()!=-1)
2057 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
2061 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2063 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2065 return const_cast<MEDCouplingUMesh *>(this);
2070 * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
2072 * 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.
2073 * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
2074 * The number of cells of \b this will remain the same with this method.
2076 * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
2077 * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
2078 * \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 ).
2079 * Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
2081 void MEDCouplingUMesh::setPartOfMySelf(const int *cellIdsBg, const int *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2083 checkConnectivityFullyDefined();
2084 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2085 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2086 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2087 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2089 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2090 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2091 throw INTERP_KERNEL::Exception(oss.str().c_str());
2093 int nbOfCellsToModify=(int)std::distance(cellIdsBg,cellIdsEnd);
2094 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2096 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2097 throw INTERP_KERNEL::Exception(oss.str().c_str());
2099 int nbOfCells=getNumberOfCells();
2100 bool easyAssign=true;
2101 const int *connI=_nodal_connec_index->getConstPointer();
2102 const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2103 for(const int *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2105 if(*it>=0 && *it<nbOfCells)
2107 easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2111 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2112 throw INTERP_KERNEL::Exception(oss.str().c_str());
2117 MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2122 DataArrayInt *arrOut=0,*arrIOut=0;
2123 MEDCouplingUMesh::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2125 MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2126 setConnectivity(arrOut,arrIOut,true);
2130 void MEDCouplingUMesh::setPartOfMySelfSlice(int start, int end, int step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2132 checkConnectivityFullyDefined();
2133 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2134 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2135 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2136 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2138 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2139 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2140 throw INTERP_KERNEL::Exception(oss.str().c_str());
2142 int nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2143 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2145 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2146 throw INTERP_KERNEL::Exception(oss.str().c_str());
2148 int nbOfCells=getNumberOfCells();
2149 bool easyAssign=true;
2150 const int *connI=_nodal_connec_index->getConstPointer();
2151 const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2153 for(int i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2155 if(it>=0 && it<nbOfCells)
2157 easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2161 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2162 throw INTERP_KERNEL::Exception(oss.str().c_str());
2167 MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2172 DataArrayInt *arrOut=0,*arrIOut=0;
2173 MEDCouplingUMesh::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2175 MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2176 setConnectivity(arrOut,arrIOut,true);
2181 * Keeps from \a this only cells which constituing point id are in the ids specified by [ \a begin,\a end ).
2182 * The resulting cell ids are stored at the end of the 'cellIdsKept' parameter.
2183 * Parameter \a fullyIn specifies if a cell that has part of its nodes in ids array is kept or not.
2184 * If \a fullyIn is true only cells whose ids are \b fully contained in [ \a begin,\a end ) tab will be kept.
2186 * \param [in] begin input start of array of node ids.
2187 * \param [in] end input end of array of node ids.
2188 * \param [in] fullyIn input that specifies if all node ids must be in [ \a begin,\a end ) array to consider cell to be in.
2189 * \param [in,out] cellIdsKeptArr array where all candidate cell ids are put at the end.
2191 void MEDCouplingUMesh::fillCellIdsToKeepFromNodeIds(const int *begin, const int *end, bool fullyIn, DataArrayInt *&cellIdsKeptArr) const
2193 MCAuto<DataArrayInt> cellIdsKept=DataArrayInt::New(); cellIdsKept->alloc(0,1);
2194 checkConnectivityFullyDefined();
2196 int sz=getNodalConnectivity()->getMaxValue(tmp); sz=std::max(sz,0)+1;
2197 std::vector<bool> fastFinder(sz,false);
2198 for(const int *work=begin;work!=end;work++)
2199 if(*work>=0 && *work<sz)
2200 fastFinder[*work]=true;
2201 int nbOfCells=getNumberOfCells();
2202 const int *conn=getNodalConnectivity()->getConstPointer();
2203 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2204 for(int i=0;i<nbOfCells;i++)
2206 int ref=0,nbOfHit=0;
2207 for(const int *work2=conn+connIndex[i]+1;work2!=conn+connIndex[i+1];work2++)
2211 if(fastFinder[*work2])
2214 if((ref==nbOfHit && fullyIn) || (nbOfHit!=0 && !fullyIn))
2215 cellIdsKept->pushBackSilent(i);
2217 cellIdsKeptArr=cellIdsKept.retn();
2221 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2222 * this->getMeshDimension(), that bound some cells of \a this mesh.
2223 * The cells of lower dimension to include to the result mesh are selected basing on
2224 * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2225 * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2226 * ==\c false, a cell is copied if any its node is in the array of node ids. The
2227 * created mesh shares the node coordinates array with \a this mesh.
2228 * \param [in] begin - the array of node ids.
2229 * \param [in] end - a pointer to the (last+1)-th element of \a begin.
2230 * \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2231 * array \a begin are added, else cells whose any node is in the
2232 * array \a begin are added.
2233 * \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2234 * to delete this mesh using decrRef() as it is no more needed.
2235 * \throw If the coordinates array is not set.
2236 * \throw If the nodal connectivity of cells is not defined.
2237 * \throw If any node id in \a begin is not valid.
2239 * \if ENABLE_EXAMPLES
2240 * \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2241 * \ref py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2244 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const int *begin, const int *end, bool fullyIn) const
2246 MCAuto<DataArrayInt> desc,descIndx,revDesc,revDescIndx;
2247 desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=DataArrayInt::New(); revDescIndx=DataArrayInt::New();
2248 MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2249 desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2250 return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2254 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2255 * this->getMeshDimension(), which bound only one cell of \a this mesh.
2256 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2257 * array of \a this mesh, else "free" nodes are removed from the result mesh
2258 * by calling zipCoords().
2259 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2260 * to delete this mesh using decrRef() as it is no more needed.
2261 * \throw If the coordinates array is not set.
2262 * \throw If the nodal connectivity of cells is not defined.
2264 * \if ENABLE_EXAMPLES
2265 * \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2266 * \ref py_mcumesh_buildBoundaryMesh "Here is a Python example".
2269 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2271 DataArrayInt *desc=DataArrayInt::New();
2272 DataArrayInt *descIndx=DataArrayInt::New();
2273 DataArrayInt *revDesc=DataArrayInt::New();
2274 DataArrayInt *revDescIndx=DataArrayInt::New();
2276 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2279 descIndx->decrRef();
2280 int nbOfCells=meshDM1->getNumberOfCells();
2281 const int *revDescIndxC=revDescIndx->getConstPointer();
2282 std::vector<int> boundaryCells;
2283 for(int i=0;i<nbOfCells;i++)
2284 if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2285 boundaryCells.push_back(i);
2286 revDescIndx->decrRef();
2287 MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2292 * This method returns a newly created DataArrayInt instance containing ids of cells located in boundary.
2293 * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2294 * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2296 DataArrayInt *MEDCouplingUMesh::findCellIdsOnBoundary() const
2298 checkFullyDefined();
2299 MCAuto<DataArrayInt> desc=DataArrayInt::New();
2300 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2301 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2302 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2304 buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2305 desc=(DataArrayInt*)0; descIndx=(DataArrayInt*)0;
2307 MCAuto<DataArrayInt> tmp=revDescIndx->deltaShiftIndex();
2308 MCAuto<DataArrayInt> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayInt*)0;
2309 const int *revDescPtr=revDesc->getConstPointer();
2310 const int *revDescIndxPtr=revDescIndx->getConstPointer();
2311 int nbOfCells=getNumberOfCells();
2312 std::vector<bool> ret1(nbOfCells,false);
2314 for(const int *pt=faceIds->begin();pt!=faceIds->end();pt++)
2315 if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2316 { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2318 DataArrayInt *ret2=DataArrayInt::New();
2320 int *ret2Ptr=ret2->getPointer();
2322 for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2325 ret2->setName("BoundaryCells");
2330 * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2331 * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2332 * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2333 * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2335 * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2336 * 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
2337 * equals a cell in \b otherDimM1OnSameCoords.
2339 * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2340 * are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2342 * \param [in] otherDimM1OnSameCoords
2343 * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2344 * \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
2345 * cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2347 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *&cellIdsRk0, DataArrayInt *&cellIdsRk1) const
2349 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2350 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2351 checkConnectivityFullyDefined();
2352 otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2353 if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2354 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2355 MCAuto<DataArrayInt> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2356 MCAuto<DataArrayInt> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2357 MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2358 MCAuto<DataArrayInt> descThisPart=DataArrayInt::New(),descIThisPart=DataArrayInt::New(),revDescThisPart=DataArrayInt::New(),revDescIThisPart=DataArrayInt::New();
2359 MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2360 const int *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2361 DataArrayInt *idsOtherInConsti=0;
2362 bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2363 MCAuto<DataArrayInt> idsOtherInConstiAuto(idsOtherInConsti);
2365 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2367 for(const int *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2368 s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2369 MCAuto<DataArrayInt> s1arr_renum1=DataArrayInt::New(); s1arr_renum1->alloc((int)s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2370 s1arr_renum1->sort();
2371 cellIdsRk0=s0arr.retn();
2372 //cellIdsRk1=s_renum1.retn();
2373 cellIdsRk1=s1arr_renum1.retn();
2377 * 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
2378 * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2380 * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2382 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2384 MCAuto<DataArrayInt> desc=DataArrayInt::New();
2385 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2386 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2387 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2389 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2390 revDesc=0; desc=0; descIndx=0;
2391 MCAuto<DataArrayInt> revDescIndx2=revDescIndx->deltaShiftIndex();
2392 MCAuto<DataArrayInt> part=revDescIndx2->findIdsEqual(1);
2393 return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2397 * Finds nodes lying on the boundary of \a this mesh.
2398 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of found
2399 * nodes. The caller is to delete this array using decrRef() as it is no
2401 * \throw If the coordinates array is not set.
2402 * \throw If the nodal connectivity of cells is node defined.
2404 * \if ENABLE_EXAMPLES
2405 * \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2406 * \ref py_mcumesh_findBoundaryNodes "Here is a Python example".
2409 DataArrayInt *MEDCouplingUMesh::findBoundaryNodes() const
2411 MCAuto<MEDCouplingUMesh> skin=computeSkin();
2412 return skin->computeFetchedNodeIds();
2415 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2418 return const_cast<MEDCouplingUMesh *>(this);
2422 * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2423 * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2424 * 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.
2425 * 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.
2426 * 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.
2428 * \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
2429 * parameter is altered during the call.
2430 * \param [out] nodeIdsToDuplicate node ids needed to be duplicated following the algorithm explain above.
2431 * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2432 * \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.
2434 * \warning This method modifies param \b otherDimM1OnSameCoords (for speed reasons).
2436 void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *& nodeIdsToDuplicate,
2437 DataArrayInt *& cellIdsNeededToBeRenum, DataArrayInt *& cellIdsNotModified) const
2439 typedef MCAuto<DataArrayInt> DAInt;
2440 typedef MCAuto<MEDCouplingUMesh> MCUMesh;
2442 checkFullyDefined();
2443 otherDimM1OnSameCoords.checkFullyDefined();
2444 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2445 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2446 if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2447 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2449 // Checking star-shaped M1 group:
2450 DAInt dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2451 MCUMesh meshM2 = otherDimM1OnSameCoords.buildDescendingConnectivity(dt0, dit0, rdt0, rdit0);
2452 DAInt dsi = rdit0->deltaShiftIndex();
2453 DAInt idsTmp0 = dsi->findIdsNotInRange(-1, 3);
2454 if(idsTmp0->getNumberOfTuples())
2455 throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2456 dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2458 // Get extreme nodes from the group (they won't be duplicated), ie nodes belonging to boundary cells of M1
2459 DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2460 MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2461 DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2462 // Remove from the list points on the boundary of the M0 mesh (those need duplication!)
2463 dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2464 MCUMesh m0desc = buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0;
2465 dsi = rdit0->deltaShiftIndex();
2466 DAInt boundSegs = dsi->findIdsEqual(1); // boundary segs/faces of the M0 mesh
2467 MCUMesh m0descSkin = static_cast<MEDCouplingUMesh *>(m0desc->buildPartOfMySelf(boundSegs->begin(),boundSegs->end(), true));
2468 DAInt fNodes = m0descSkin->computeFetchedNodeIds();
2469 // In 3D, some points on the boundary of M0 still need duplication:
2471 if (getMeshDimension() == 3)
2473 DAInt dnu1=DataArrayInt::New(), dnu2=DataArrayInt::New(), dnu3=DataArrayInt::New(), dnu4=DataArrayInt::New();
2474 MCUMesh m0descSkinDesc = m0descSkin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4);
2475 dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2476 DataArrayInt * corresp=0;
2477 meshM2->areCellsIncludedIn(m0descSkinDesc,2,corresp);
2478 DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2480 if (validIds->getNumberOfTuples())
2482 MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0descSkinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2483 DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2484 DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2485 notDup = xtrem->buildSubstraction(fNodes1);
2488 notDup = xtrem->buildSubstraction(fNodes);
2491 notDup = xtrem->buildSubstraction(fNodes);
2493 // Now compute cells around group (i.e. cells where we will do the propagation to identify the two sub-sets delimited by the group)
2494 DAInt m1Nodes = otherDimM1OnSameCoords.computeFetchedNodeIds();
2495 DAInt dupl = m1Nodes->buildSubstraction(notDup);
2496 DAInt cellsAroundGroup = getCellIdsLyingOnNodes(dupl->begin(), dupl->end(), false); // false= take cell in, even if not all nodes are in notDup
2499 MCUMesh m0Part2=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroup->begin(),cellsAroundGroup->end(),true));
2500 int nCells2 = m0Part2->getNumberOfCells();
2501 DAInt desc00=DataArrayInt::New(),descI00=DataArrayInt::New(),revDesc00=DataArrayInt::New(),revDescI00=DataArrayInt::New();
2502 MCUMesh m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00);
2504 // Neighbor information of the mesh without considering the crack (serves to count how many connex pieces it is made of)
2505 DataArrayInt *tmp00=0,*tmp11=0;
2506 MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00, tmp00, tmp11);
2507 DAInt neighInit00(tmp00);
2508 DAInt neighIInit00(tmp11);
2509 // Neighbor information of the mesh WITH the crack (some neighbors are removed):
2510 DataArrayInt *idsTmp=0;
2511 bool b=m01->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsTmp);
2513 // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2514 // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2515 MEDCouplingUMesh::RemoveIdsFromIndexedArrays(ids->begin(),ids->end(),desc00,descI00);
2516 DataArrayInt *tmp0=0,*tmp1=0;
2517 // Compute the neighbor of each cell in m0Part2, taking into account the broken link above. Two
2518 // cells on either side of the crack (defined by the mesh of low dimension) are not neighbor anymore.
2519 ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00,tmp0,tmp1);
2520 DAInt neigh00(tmp0);
2521 DAInt neighI00(tmp1);
2523 // For each initial connex part of the sub-mesh (or said differently for each independent crack):
2524 int seed = 0, nIter = 0;
2525 int nIterMax = nCells2+1; // Safety net for the loop
2526 DAInt hitCells = DataArrayInt::New(); hitCells->alloc(nCells2);
2527 hitCells->fillWithValue(-1);
2528 DAInt cellsToModifyConn0_torenum = DataArrayInt::New();
2529 cellsToModifyConn0_torenum->alloc(0,1);
2530 while (nIter < nIterMax)
2532 DAInt t = hitCells->findIdsEqual(-1);
2533 if (!t->getNumberOfTuples())
2535 // Connex zone without the crack (to compute the next seed really)
2537 DAInt connexCheck = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neighInit00,neighIInit00, -1, dnu);
2539 for (int * ptr = connexCheck->getPointer(); cnt < connexCheck->getNumberOfTuples(); ptr++, cnt++)
2540 hitCells->setIJ(*ptr,0,1);
2541 // Connex zone WITH the crack (to identify cells lying on either part of the crack)
2542 DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neigh00,neighI00, -1, dnu);
2543 cellsToModifyConn0_torenum = DataArrayInt::Aggregate(cellsToModifyConn0_torenum, spreadZone, 0);
2544 // Compute next seed, i.e. a cell in another connex part, which was not covered by the previous iterations
2545 DAInt comple = cellsToModifyConn0_torenum->buildComplement(nCells2);
2546 DAInt nonHitCells = hitCells->findIdsEqual(-1);
2547 DAInt intersec = nonHitCells->buildIntersection(comple);
2548 if (intersec->getNumberOfTuples())
2549 { seed = intersec->getIJ(0,0); }
2554 if (nIter >= nIterMax)
2555 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate(): internal error - too many iterations.");
2557 DAInt cellsToModifyConn1_torenum=cellsToModifyConn0_torenum->buildComplement(neighI00->getNumberOfTuples()-1);
2558 cellsToModifyConn0_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2559 cellsToModifyConn1_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2561 cellIdsNeededToBeRenum=cellsToModifyConn0_torenum.retn();
2562 cellIdsNotModified=cellsToModifyConn1_torenum.retn();
2563 nodeIdsToDuplicate=dupl.retn();
2567 * This method operates a modification of the connectivity and coords in \b this.
2568 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2569 * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2570 * 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
2571 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2572 * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2574 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2576 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2577 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2579 void MEDCouplingUMesh::duplicateNodes(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd)
2581 int nbOfNodes=getNumberOfNodes();
2582 duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2583 duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2587 * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2588 * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2590 * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2592 * \sa renumberNodesInConn
2594 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(int offset)
2596 checkConnectivityFullyDefined();
2597 int *conn(getNodalConnectivity()->getPointer());
2598 const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2599 int nbOfCells(getNumberOfCells());
2600 for(int i=0;i<nbOfCells;i++)
2601 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2603 int& node=conn[iconn];
2604 if(node>=0)//avoid polyhedron separator
2609 _nodal_connec->declareAsNew();
2614 * Same than renumberNodesInConn(const int *) except that here the format of old-to-new traducer is using map instead
2615 * 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
2618 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<int,int>& newNodeNumbersO2N)
2620 checkConnectivityFullyDefined();
2621 int *conn(getNodalConnectivity()->getPointer());
2622 const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2623 int nbOfCells(getNumberOfCells());
2624 for(int i=0;i<nbOfCells;i++)
2625 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2627 int& node=conn[iconn];
2628 if(node>=0)//avoid polyhedron separator
2630 INTERP_KERNEL::HashMap<int,int>::const_iterator it(newNodeNumbersO2N.find(node));
2631 if(it!=newNodeNumbersO2N.end())
2637 std::ostringstream oss; oss << "MEDCouplingUMesh::renumberNodesInConn(map) : presence in connectivity for cell #" << i << " of node #" << node << " : Not in map !";
2638 throw INTERP_KERNEL::Exception(oss.str().c_str());
2642 _nodal_connec->declareAsNew();
2647 * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2648 * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2649 * This method is a generalization of shiftNodeNumbersInConn().
2650 * \warning This method performs no check of validity of new ids. **Use it with care !**
2651 * \param [in] newNodeNumbersO2N - a permutation array, of length \a
2652 * this->getNumberOfNodes(), in "Old to New" mode.
2653 * See \ref numbering for more info on renumbering modes.
2654 * \throw If the nodal connectivity of cells is not defined.
2656 * \if ENABLE_EXAMPLES
2657 * \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2658 * \ref py_mcumesh_renumberNodesInConn "Here is a Python example".
2661 void MEDCouplingUMesh::renumberNodesInConn(const int *newNodeNumbersO2N)
2663 checkConnectivityFullyDefined();
2664 int *conn=getNodalConnectivity()->getPointer();
2665 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2666 int nbOfCells(getNumberOfCells());
2667 for(int i=0;i<nbOfCells;i++)
2668 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2670 int& node=conn[iconn];
2671 if(node>=0)//avoid polyhedron separator
2673 node=newNodeNumbersO2N[node];
2676 _nodal_connec->declareAsNew();
2681 * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2682 * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2683 * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2685 * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2687 void MEDCouplingUMesh::shiftNodeNumbersInConn(int delta)
2689 checkConnectivityFullyDefined();
2690 int *conn=getNodalConnectivity()->getPointer();
2691 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2692 int nbOfCells=getNumberOfCells();
2693 for(int i=0;i<nbOfCells;i++)
2694 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2696 int& node=conn[iconn];
2697 if(node>=0)//avoid polyhedron separator
2702 _nodal_connec->declareAsNew();
2707 * This method operates a modification of the connectivity in \b this.
2708 * 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.
2709 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2710 * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2711 * 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
2712 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2713 * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2715 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2716 * As an another consequense after the call of this method \b this can be transiently non cohrent.
2718 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2719 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2720 * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ).
2722 void MEDCouplingUMesh::duplicateNodesInConn(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd, int offset)
2724 checkConnectivityFullyDefined();
2725 std::map<int,int> m;
2727 for(const int *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2729 int *conn=getNodalConnectivity()->getPointer();
2730 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2731 int nbOfCells=getNumberOfCells();
2732 for(int i=0;i<nbOfCells;i++)
2733 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2735 int& node=conn[iconn];
2736 if(node>=0)//avoid polyhedron separator
2738 std::map<int,int>::iterator it=m.find(node);
2747 * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2749 * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2750 * After the call of this method the number of cells remains the same as before.
2752 * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2753 * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2754 * be strictly in [0;this->getNumberOfCells()).
2756 * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2757 * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2758 * should be contained in[0;this->getNumberOfCells()).
2760 * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2763 void MEDCouplingUMesh::renumberCells(const int *old2NewBg, bool check)
2765 checkConnectivityFullyDefined();
2766 int nbCells=getNumberOfCells();
2767 const int *array=old2NewBg;
2769 array=DataArrayInt::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2771 const int *conn=_nodal_connec->getConstPointer();
2772 const int *connI=_nodal_connec_index->getConstPointer();
2773 MCAuto<DataArrayInt> o2n=DataArrayInt::New(); o2n->useArray(array,false,C_DEALLOC,nbCells,1);
2774 MCAuto<DataArrayInt> n2o=o2n->invertArrayO2N2N2O(nbCells);
2775 const int *n2oPtr=n2o->begin();
2776 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
2777 newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2778 newConn->copyStringInfoFrom(*_nodal_connec);
2779 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
2780 newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2781 newConnI->copyStringInfoFrom(*_nodal_connec_index);
2783 int *newC=newConn->getPointer();
2784 int *newCI=newConnI->getPointer();
2787 for(int i=0;i<nbCells;i++)
2790 int nbOfElts=connI[pos+1]-connI[pos];
2791 newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2796 setConnectivity(newConn,newConnI);
2798 free(const_cast<int *>(array));
2802 * Finds cells whose bounding boxes intersect a given bounding box.
2803 * \param [in] bbox - an array defining the bounding box via coordinates of its
2804 * extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2806 * \param [in] eps - a factor used to increase size of the bounding box of cell
2807 * before comparing it with \a bbox. This factor is multiplied by the maximal
2808 * extent of the bounding box of cell to produce an addition to this bounding box.
2809 * \return DataArrayInt * - a new instance of DataArrayInt holding ids for found
2810 * cells. The caller is to delete this array using decrRef() as it is no more
2812 * \throw If the coordinates array is not set.
2813 * \throw If the nodal connectivity of cells is not defined.
2815 * \if ENABLE_EXAMPLES
2816 * \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2817 * \ref py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2820 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2822 MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2823 if(getMeshDimension()==-1)
2825 elems->pushBackSilent(0);
2826 return elems.retn();
2828 int dim=getSpaceDimension();
2829 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2830 const int* conn = getNodalConnectivity()->getConstPointer();
2831 const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2832 const double* coords = getCoords()->getConstPointer();
2833 int nbOfCells=getNumberOfCells();
2834 for ( int ielem=0; ielem<nbOfCells;ielem++ )
2836 for (int i=0; i<dim; i++)
2838 elem_bb[i*2]=std::numeric_limits<double>::max();
2839 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2842 for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2844 int node= conn[inode];
2845 if(node>=0)//avoid polyhedron separator
2847 for (int idim=0; idim<dim; idim++)
2849 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2851 elem_bb[idim*2] = coords[node*dim+idim] ;
2853 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2855 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2860 if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2861 elems->pushBackSilent(ielem);
2863 return elems.retn();
2867 * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2868 * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2869 * added in 'elems' parameter.
2871 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2873 MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2874 if(getMeshDimension()==-1)
2876 elems->pushBackSilent(0);
2877 return elems.retn();
2879 int dim=getSpaceDimension();
2880 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2881 const int* conn = getNodalConnectivity()->getConstPointer();
2882 const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2883 const double* coords = getCoords()->getConstPointer();
2884 int nbOfCells=getNumberOfCells();
2885 for ( int ielem=0; ielem<nbOfCells;ielem++ )
2887 for (int i=0; i<dim; i++)
2889 elem_bb[i*2]=std::numeric_limits<double>::max();
2890 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2893 for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2895 int node= conn[inode];
2896 if(node>=0)//avoid polyhedron separator
2898 for (int idim=0; idim<dim; idim++)
2900 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2902 elem_bb[idim*2] = coords[node*dim+idim] ;
2904 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2906 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2911 if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
2912 elems->pushBackSilent(ielem);
2914 return elems.retn();
2918 * Returns a type of a cell by its id.
2919 * \param [in] cellId - the id of the cell of interest.
2920 * \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
2921 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2923 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(int cellId) const
2925 const int *ptI=_nodal_connec_index->getConstPointer();
2926 const int *pt=_nodal_connec->getConstPointer();
2927 if(cellId>=0 && cellId<(int)_nodal_connec_index->getNbOfElems()-1)
2928 return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2931 std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2932 throw INTERP_KERNEL::Exception(oss.str().c_str());
2937 * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2938 * This method does not throw exception if geometric type \a type is not in \a this.
2939 * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2940 * The coordinates array is not considered here.
2942 * \param [in] type the geometric type
2943 * \return cell ids in this having geometric type \a type.
2945 DataArrayInt *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2948 MCAuto<DataArrayInt> ret=DataArrayInt::New();
2950 checkConnectivityFullyDefined();
2951 int nbCells=getNumberOfCells();
2952 int mdim=getMeshDimension();
2953 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
2954 if(mdim!=(int)cm.getDimension())
2955 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
2956 const int *ptI=_nodal_connec_index->getConstPointer();
2957 const int *pt=_nodal_connec->getConstPointer();
2958 for(int i=0;i<nbCells;i++)
2960 if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
2961 ret->pushBackSilent(i);
2967 * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
2969 int MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2971 const int *ptI=_nodal_connec_index->getConstPointer();
2972 const int *pt=_nodal_connec->getConstPointer();
2973 int nbOfCells=getNumberOfCells();
2975 for(int i=0;i<nbOfCells;i++)
2976 if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
2982 * Returns the nodal connectivity of a given cell.
2983 * The separator of faces within polyhedron connectivity (-1) is not returned, thus
2984 * all returned node ids can be used in getCoordinatesOfNode().
2985 * \param [in] cellId - an id of the cell of interest.
2986 * \param [in,out] conn - a vector where the node ids are appended. It is not
2987 * cleared before the appending.
2988 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2990 void MEDCouplingUMesh::getNodeIdsOfCell(int cellId, std::vector<int>& conn) const
2992 const int *ptI=_nodal_connec_index->getConstPointer();
2993 const int *pt=_nodal_connec->getConstPointer();
2994 for(const int *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
2999 std::string MEDCouplingUMesh::simpleRepr() const
3001 static const char msg0[]="No coordinates specified !";
3002 std::ostringstream ret;
3003 ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
3004 ret << "Description of mesh : \"" << getDescription() << "\"\n";
3006 double tt=getTime(tmpp1,tmpp2);
3007 ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
3008 ret << "Iteration : " << tmpp1 << " Order : " << tmpp2 << "\n";
3010 { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
3012 { ret << " Mesh dimension has not been set or is invalid !"; }
3015 const int spaceDim=getSpaceDimension();
3016 ret << spaceDim << "\nInfo attached on space dimension : ";
3017 for(int i=0;i<spaceDim;i++)
3018 ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
3022 ret << msg0 << "\n";
3023 ret << "Number of nodes : ";
3025 ret << getNumberOfNodes() << "\n";
3027 ret << msg0 << "\n";
3028 ret << "Number of cells : ";
3029 if(_nodal_connec!=0 && _nodal_connec_index!=0)
3030 ret << getNumberOfCells() << "\n";
3032 ret << "No connectivity specified !" << "\n";
3033 ret << "Cell types present : ";
3034 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
3036 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
3037 ret << cm.getRepr() << " ";
3043 std::string MEDCouplingUMesh::advancedRepr() const
3045 std::ostringstream ret;
3046 ret << simpleRepr();
3047 ret << "\nCoordinates array : \n___________________\n\n";
3049 _coords->reprWithoutNameStream(ret);
3051 ret << "No array set !\n";
3052 ret << "\n\nConnectivity arrays : \n_____________________\n\n";
3053 reprConnectivityOfThisLL(ret);
3058 * This method returns a C++ code that is a dump of \a this.
3059 * This method will throw if this is not fully defined.
3061 std::string MEDCouplingUMesh::cppRepr() const
3063 static const char coordsName[]="coords";
3064 static const char connName[]="conn";
3065 static const char connIName[]="connI";
3066 checkFullyDefined();
3067 std::ostringstream ret; ret << "// coordinates" << std::endl;
3068 _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
3069 _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
3070 _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
3071 ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
3072 ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
3073 ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
3074 ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
3078 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
3080 std::ostringstream ret;
3081 reprConnectivityOfThisLL(ret);
3086 * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsability to deal with.
3087 * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
3088 * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
3091 * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
3092 * 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
3093 * with number of tuples set to 0, if not the array is taken as this in the returned instance.
3095 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(int spaceDim) const
3097 int mdim=getMeshDimension();
3099 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
3100 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
3101 MCAuto<DataArrayInt> tmp1,tmp2;
3102 bool needToCpyCT=true;
3105 tmp1=DataArrayInt::New(); tmp1->alloc(0,1);
3113 if(!_nodal_connec_index)
3115 tmp2=DataArrayInt::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
3120 tmp2=_nodal_connec_index;
3123 ret->setConnectivity(tmp1,tmp2,false);
3128 MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
3129 ret->setCoords(coords);
3132 ret->setCoords(_coords);
3136 void MEDCouplingUMesh::reprConnectivityOfThisLL(std::ostringstream& stream) const
3138 if(_nodal_connec!=0 && _nodal_connec_index!=0)
3140 int nbOfCells=getNumberOfCells();
3141 const int *c=_nodal_connec->getConstPointer();
3142 const int *ci=_nodal_connec_index->getConstPointer();
3143 for(int i=0;i<nbOfCells;i++)
3145 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[i]]);
3146 stream << "Cell #" << i << " " << cm.getRepr() << " : ";
3147 std::copy(c+ci[i]+1,c+ci[i+1],std::ostream_iterator<int>(stream," "));
3152 stream << "Connectivity not defined !\n";
3155 int MEDCouplingUMesh::getNumberOfNodesInCell(int cellId) const
3157 const int *ptI=_nodal_connec_index->getConstPointer();
3158 const int *pt=_nodal_connec->getConstPointer();
3159 if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
3160 return ptI[cellId+1]-ptI[cellId]-1;
3162 return (int)std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind2nd(std::not_equal_to<int>(),-1));
3166 * Returns types of cells of the specified part of \a this mesh.
3167 * This method avoids computing sub-mesh explicitely to get its types.
3168 * \param [in] begin - an array of cell ids of interest.
3169 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3170 * \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3171 * describing the cell types.
3172 * \throw If the coordinates array is not set.
3173 * \throw If the nodal connectivity of cells is not defined.
3174 * \sa getAllGeoTypes()
3176 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const int *begin, const int *end) const
3178 checkFullyDefined();
3179 std::set<INTERP_KERNEL::NormalizedCellType> ret;
3180 const int *conn=_nodal_connec->getConstPointer();
3181 const int *connIndex=_nodal_connec_index->getConstPointer();
3182 for(const int *w=begin;w!=end;w++)
3183 ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3188 * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3189 * Optionally updates
3190 * a set of types of cells constituting \a this mesh.
3191 * This method is for advanced users having prepared their connectivity before. For
3192 * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3193 * \param [in] conn - the nodal connectivity array.
3194 * \param [in] connIndex - the nodal connectivity index array.
3195 * \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3198 void MEDCouplingUMesh::setConnectivity(DataArrayInt *conn, DataArrayInt *connIndex, bool isComputingTypes)
3200 DataArrayInt::SetArrayIn(conn,_nodal_connec);
3201 DataArrayInt::SetArrayIn(connIndex,_nodal_connec_index);
3202 if(isComputingTypes)
3208 * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3209 * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3211 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCopy):MEDCouplingPointSet(other,deepCopy),_mesh_dim(other._mesh_dim),
3212 _nodal_connec(0),_nodal_connec_index(0),
3213 _types(other._types)
3215 if(other._nodal_connec)
3216 _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCopy);
3217 if(other._nodal_connec_index)
3218 _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCopy);
3221 MEDCouplingUMesh::~MEDCouplingUMesh()
3224 _nodal_connec->decrRef();
3225 if(_nodal_connec_index)
3226 _nodal_connec_index->decrRef();
3230 * Recomputes a set of cell types of \a this mesh. For more info see
3231 * \ref MEDCouplingUMeshNodalConnectivity.
3233 void MEDCouplingUMesh::computeTypes()
3235 ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3239 * This method checks that all arrays are set. If yes nothing done if no an exception is thrown.
3241 void MEDCouplingUMesh::checkFullyDefined() const
3243 if(!_nodal_connec_index || !_nodal_connec || !_coords)
3244 throw INTERP_KERNEL::Exception("Reverse nodal connectivity computation requires full connectivity and coordinates set in unstructured mesh.");
3248 * This method checks that all connectivity arrays are set. If yes nothing done if no an exception is thrown.
3250 void MEDCouplingUMesh::checkConnectivityFullyDefined() const
3252 if(!_nodal_connec_index || !_nodal_connec)
3253 throw INTERP_KERNEL::Exception("Reverse nodal connectivity computation requires full connectivity set in unstructured mesh.");
3257 * Returns a number of cells constituting \a this mesh.
3258 * \return int - the number of cells in \a this mesh.
3259 * \throw If the nodal connectivity of cells is not defined.
3261 int MEDCouplingUMesh::getNumberOfCells() const
3263 if(_nodal_connec_index)
3264 return _nodal_connec_index->getNumberOfTuples()-1;
3269 throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3273 * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3274 * mesh. For more info see \ref meshes.
3275 * \return int - the dimension of \a this mesh.
3276 * \throw If the mesh dimension is not defined using setMeshDimension().
3278 int MEDCouplingUMesh::getMeshDimension() const
3281 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3286 * Returns a length of the nodal connectivity array.
3287 * This method is for test reason. Normally the integer returned is not useable by
3288 * user. For more info see \ref MEDCouplingUMeshNodalConnectivity.
3289 * \return int - the length of the nodal connectivity array.
3291 int MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3293 return _nodal_connec->getNbOfElems();
3297 * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3299 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<int>& tinyInfo, std::vector<std::string>& littleStrings) const
3301 MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3302 tinyInfo.push_back(getMeshDimension());
3303 tinyInfo.push_back(getNumberOfCells());
3305 tinyInfo.push_back(getNodalConnectivityArrayLen());
3307 tinyInfo.push_back(-1);
3311 * First step of unserialization process.
3313 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<int>& tinyInfo) const
3315 return tinyInfo[6]<=0;
3319 * Second step of serialization process.
3320 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3323 * \param littleStrings
3325 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<int>& tinyInfo, DataArrayInt *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3327 MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3329 a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3333 * Third and final step of serialization process.
3335 void MEDCouplingUMesh::serialize(DataArrayInt *&a1, DataArrayDouble *&a2) const
3337 MEDCouplingPointSet::serialize(a1,a2);
3338 if(getMeshDimension()>-1)
3340 a1=DataArrayInt::New();
3341 a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3342 int *ptA1=a1->getPointer();
3343 const int *conn=getNodalConnectivity()->getConstPointer();
3344 const int *index=getNodalConnectivityIndex()->getConstPointer();
3345 ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3346 std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3353 * Second and final unserialization process.
3354 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3356 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<int>& tinyInfo, const DataArrayInt *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3358 MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3359 setMeshDimension(tinyInfo[5]);
3363 const int *recvBuffer=a1->getConstPointer();
3364 MCAuto<DataArrayInt> myConnecIndex=DataArrayInt::New();
3365 myConnecIndex->alloc(tinyInfo[6]+1,1);
3366 std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3367 MCAuto<DataArrayInt> myConnec=DataArrayInt::New();
3368 myConnec->alloc(tinyInfo[7],1);
3369 std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3370 setConnectivity(myConnec, myConnecIndex);
3375 * This is the low algorithm of MEDCouplingUMesh::buildPartOfMySelfSlice.
3376 * CellIds are given using range specified by a start an end and step.
3378 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice(int start, int end, int step) const
3380 checkFullyDefined();
3381 int ncell=getNumberOfCells();
3382 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New();
3383 ret->_mesh_dim=_mesh_dim;
3384 ret->setCoords(_coords);
3385 int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice : ");
3386 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(newNbOfCells+1,1);
3387 int *newConnIPtr=newConnI->getPointer(); *newConnIPtr=0;
3389 const int *conn=_nodal_connec->getConstPointer();
3390 const int *connIndex=_nodal_connec_index->getConstPointer();
3391 for(int i=0;i<newNbOfCells;i++,newConnIPtr++,work+=step)
3393 if(work>=0 && work<ncell)
3395 newConnIPtr[1]=newConnIPtr[0]+connIndex[work+1]-connIndex[work];
3399 std::ostringstream oss; oss << "MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice : On pos #" << i << " input cell id =" << work << " should be in [0," << ncell << ") !";
3400 throw INTERP_KERNEL::Exception(oss.str().c_str());
3403 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(newConnIPtr[0],1);
3404 int *newConnPtr=newConn->getPointer();
3405 std::set<INTERP_KERNEL::NormalizedCellType> types;
3407 for(int i=0;i<newNbOfCells;i++,newConnIPtr++,work+=step)
3409 types.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[work]]);
3410 newConnPtr=std::copy(conn+connIndex[work],conn+connIndex[work+1],newConnPtr);
3412 ret->setConnectivity(newConn,newConnI,false);
3414 ret->copyTinyInfoFrom(this);
3419 * This is the low algorithm of MEDCouplingUMesh::buildPartOfMySelf.
3420 * Keeps from \a this only cells which constituing point id are in the ids specified by [ \a begin,\a end ).
3421 * The return newly allocated mesh will share the same coordinates as \a this.
3423 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfKeepCoords(const int *begin, const int *end) const
3425 checkConnectivityFullyDefined();
3426 int ncell=getNumberOfCells();
3427 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New();
3428 ret->_mesh_dim=_mesh_dim;
3429 ret->setCoords(_coords);
3430 std::size_t nbOfElemsRet=std::distance(begin,end);
3431 int *connIndexRet=(int *)malloc((nbOfElemsRet+1)*sizeof(int));
3433 const int *conn=_nodal_connec->getConstPointer();
3434 const int *connIndex=_nodal_connec_index->getConstPointer();
3436 for(const int *work=begin;work!=end;work++,newNbring++)
3438 if(*work>=0 && *work<ncell)
3439 connIndexRet[newNbring+1]=connIndexRet[newNbring]+connIndex[*work+1]-connIndex[*work];
3443 std::ostringstream oss; oss << "MEDCouplingUMesh::buildPartOfMySelfKeepCoords : On pos #" << std::distance(begin,work) << " input cell id =" << *work << " should be in [0," << ncell << ") !";
3444 throw INTERP_KERNEL::Exception(oss.str().c_str());
3447 int *connRet=(int *)malloc(connIndexRet[nbOfElemsRet]*sizeof(int));
3448 int *connRetWork=connRet;
3449 std::set<INTERP_KERNEL::NormalizedCellType> types;
3450 for(const int *work=begin;work!=end;work++)
3452 types.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*work]]);
3453 connRetWork=std::copy(conn+connIndex[*work],conn+connIndex[*work+1],connRetWork);
3455 MCAuto<DataArrayInt> connRetArr=DataArrayInt::New();
3456 connRetArr->useArray(connRet,true,C_DEALLOC,connIndexRet[nbOfElemsRet],1);
3457 MCAuto<DataArrayInt> connIndexRetArr=DataArrayInt::New();
3458 connIndexRetArr->useArray(connIndexRet,true,C_DEALLOC,(int)nbOfElemsRet+1,1);
3459 ret->setConnectivity(connRetArr,connIndexRetArr,false);
3461 ret->copyTinyInfoFrom(this);
3466 * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3468 * For 1D cells, the returned field contains lengths.<br>
3469 * For 2D cells, the returned field contains areas.<br>
3470 * For 3D cells, the returned field contains volumes.
3471 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3472 * orientation, i.e. the volume is always positive.
3473 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3474 * and one time . The caller is to delete this field using decrRef() as it is no
3477 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3479 std::string name="MeasureOfMesh_";
3481 int nbelem=getNumberOfCells();
3482 MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3483 field->setName(name);
3484 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3485 array->alloc(nbelem,1);
3486 double *area_vol=array->getPointer();
3487 field->setArray(array) ; array=0;
3488 field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3489 field->synchronizeTimeWithMesh();
3490 if(getMeshDimension()!=-1)
3493 INTERP_KERNEL::NormalizedCellType type;
3494 int dim_space=getSpaceDimension();
3495 const double *coords=getCoords()->getConstPointer();
3496 const int *connec=getNodalConnectivity()->getConstPointer();
3497 const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3498 for(int iel=0;iel<nbelem;iel++)
3500 ipt=connec_index[iel];
3501 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3502 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);
3505 std::transform(area_vol,area_vol+nbelem,area_vol,std::ptr_fun<double,double>(fabs));
3509 area_vol[0]=std::numeric_limits<double>::max();
3511 return field.retn();
3515 * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3517 * For 1D cells, the returned array contains lengths.<br>
3518 * For 2D cells, the returned array contains areas.<br>
3519 * For 3D cells, the returned array contains volumes.
3520 * This method avoids building explicitly a part of \a this mesh to perform the work.
3521 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3522 * orientation, i.e. the volume is always positive.
3523 * \param [in] begin - an array of cell ids of interest.
3524 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3525 * \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3526 * delete this array using decrRef() as it is no more needed.
3528 * \if ENABLE_EXAMPLES
3529 * \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3530 * \ref py_mcumesh_getPartMeasureField "Here is a Python example".
3532 * \sa getMeasureField()
3534 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const int *begin, const int *end) const
3536 std::string name="PartMeasureOfMesh_";
3538 int nbelem=(int)std::distance(begin,end);
3539 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3540 array->setName(name);
3541 array->alloc(nbelem,1);
3542 double *area_vol=array->getPointer();
3543 if(getMeshDimension()!=-1)
3546 INTERP_KERNEL::NormalizedCellType type;
3547 int dim_space=getSpaceDimension();
3548 const double *coords=getCoords()->getConstPointer();
3549 const int *connec=getNodalConnectivity()->getConstPointer();
3550 const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3551 for(const int *iel=begin;iel!=end;iel++)
3553 ipt=connec_index[*iel];
3554 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3555 *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<int,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3558 std::transform(array->getPointer(),area_vol,array->getPointer(),std::ptr_fun<double,double>(fabs));
3562 area_vol[0]=std::numeric_limits<double>::max();
3564 return array.retn();
3568 * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3569 * \a this one. The returned field contains the dual cell volume for each corresponding
3570 * node in \a this mesh. In other words, the field returns the getMeasureField() of
3571 * the dual mesh in P1 sens of \a this.<br>
3572 * For 1D cells, the returned field contains lengths.<br>
3573 * For 2D cells, the returned field contains areas.<br>
3574 * For 3D cells, the returned field contains volumes.
3575 * This method is useful to check "P1*" conservative interpolators.
3576 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3577 * orientation, i.e. the volume is always positive.
3578 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3579 * nodes and one time. The caller is to delete this array using decrRef() as
3580 * it is no more needed.
3582 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3584 MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3585 std::string name="MeasureOnNodeOfMesh_";
3587 int nbNodes=getNumberOfNodes();
3588 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3589 double cst=1./((double)getMeshDimension()+1.);
3590 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3591 array->alloc(nbNodes,1);
3592 double *valsToFill=array->getPointer();
3593 std::fill(valsToFill,valsToFill+nbNodes,0.);
3594 const double *values=tmp->getArray()->getConstPointer();
3595 MCAuto<DataArrayInt> da=DataArrayInt::New();
3596 MCAuto<DataArrayInt> daInd=DataArrayInt::New();
3597 getReverseNodalConnectivity(da,daInd);
3598 const int *daPtr=da->getConstPointer();
3599 const int *daIPtr=daInd->getConstPointer();
3600 for(int i=0;i<nbNodes;i++)
3601 for(const int *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3602 valsToFill[i]+=cst*values[*cell];
3604 ret->setArray(array);
3609 * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3610 * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3611 * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3612 * and are normalized.
3613 * <br> \a this can be either
3614 * - a 2D mesh in 2D or 3D space or
3615 * - an 1D mesh in 2D space.
3617 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3618 * cells and one time. The caller is to delete this field using decrRef() as
3619 * it is no more needed.
3620 * \throw If the nodal connectivity of cells is not defined.
3621 * \throw If the coordinates array is not set.
3622 * \throw If the mesh dimension is not set.
3623 * \throw If the mesh and space dimension is not as specified above.
3625 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3627 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3628 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3629 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3630 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3631 int nbOfCells=getNumberOfCells();
3632 int nbComp=getMeshDimension()+1;
3633 array->alloc(nbOfCells,nbComp);
3634 double *vals=array->getPointer();
3635 const int *connI=_nodal_connec_index->getConstPointer();
3636 const int *conn=_nodal_connec->getConstPointer();
3637 const double *coords=_coords->getConstPointer();
3638 if(getMeshDimension()==2)
3640 if(getSpaceDimension()==3)
3642 MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3643 const double *locPtr=loc->getConstPointer();
3644 for(int i=0;i<nbOfCells;i++,vals+=3)
3646 int offset=connI[i];
3647 INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3648 double n=INTERP_KERNEL::norm<3>(vals);
3649 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3654 MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3655 const double *isAbsPtr=isAbs->getArray()->begin();
3656 for(int i=0;i<nbOfCells;i++,isAbsPtr++)
3657 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3660 else//meshdimension==1
3663 for(int i=0;i<nbOfCells;i++)
3665 int offset=connI[i];
3666 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3667 double n=INTERP_KERNEL::norm<2>(tmp);
3668 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3673 ret->setArray(array);
3675 ret->synchronizeTimeWithSupport();
3680 * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3681 * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3682 * and are normalized.
3683 * <br> \a this can be either
3684 * - a 2D mesh in 2D or 3D space or
3685 * - an 1D mesh in 2D space.
3687 * This method avoids building explicitly a part of \a this mesh to perform the work.
3688 * \param [in] begin - an array of cell ids of interest.
3689 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3690 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3691 * cells and one time. The caller is to delete this field using decrRef() as
3692 * it is no more needed.
3693 * \throw If the nodal connectivity of cells is not defined.
3694 * \throw If the coordinates array is not set.
3695 * \throw If the mesh dimension is not set.
3696 * \throw If the mesh and space dimension is not as specified above.
3697 * \sa buildOrthogonalField()
3699 * \if ENABLE_EXAMPLES
3700 * \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3701 * \ref py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3704 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const int *begin, const int *end) const
3706 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3707 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3708 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3709 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3710 std::size_t nbelems=std::distance(begin,end);
3711 int nbComp=getMeshDimension()+1;
3712 array->alloc((int)nbelems,nbComp);
3713 double *vals=array->getPointer();
3714 const int *connI=_nodal_connec_index->getConstPointer();
3715 const int *conn=_nodal_connec->getConstPointer();
3716 const double *coords=_coords->getConstPointer();
3717 if(getMeshDimension()==2)
3719 if(getSpaceDimension()==3)
3721 MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3722 const double *locPtr=loc->getConstPointer();
3723 for(const int *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3725 int offset=connI[*i];
3726 INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3727 double n=INTERP_KERNEL::norm<3>(vals);
3728 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3733 for(std::size_t i=0;i<nbelems;i++)
3734 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3737 else//meshdimension==1
3740 for(const int *i=begin;i!=end;i++)
3742 int offset=connI[*i];
3743 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3744 double n=INTERP_KERNEL::norm<2>(tmp);
3745 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3750 ret->setArray(array);
3752 ret->synchronizeTimeWithSupport();
3757 * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3758 * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3759 * and are \b not normalized.
3760 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3761 * cells and one time. The caller is to delete this field using decrRef() as
3762 * it is no more needed.
3763 * \throw If the nodal connectivity of cells is not defined.
3764 * \throw If the coordinates array is not set.
3765 * \throw If \a this->getMeshDimension() != 1.
3766 * \throw If \a this mesh includes cells of type other than SEG2.
3768 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3770 if(getMeshDimension()!=1)
3771 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3772 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3773 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3774 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3775 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3776 int nbOfCells=getNumberOfCells();
3777 int spaceDim=getSpaceDimension();
3778 array->alloc(nbOfCells,spaceDim);
3779 double *pt=array->getPointer();
3780 const double *coo=getCoords()->getConstPointer();
3781 std::vector<int> conn;
3783 for(int i=0;i<nbOfCells;i++)
3786 getNodeIdsOfCell(i,conn);
3787 pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3789 ret->setArray(array);
3791 ret->synchronizeTimeWithSupport();
3796 * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3797 * returns a new DataArrayInt, of length equal to the number of 2D cells in the result
3798 * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3799 * from. If a result face is shared by two 3D cells, then the face in included twice in
3801 * \param [in] origin - 3 components of a point defining location of the plane.
3802 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3803 * must be greater than 1e-6.
3804 * \param [in] eps - half-thickness of the plane.
3805 * \param [out] cellIds - a new instance of DataArrayInt holding ids of 3D cells
3806 * producing correspondent 2D cells. The caller is to delete this array
3807 * using decrRef() as it is no more needed.
3808 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3809 * not share the node coordinates array with \a this mesh. The caller is to
3810 * delete this mesh using decrRef() as it is no more needed.
3811 * \throw If the coordinates array is not set.
3812 * \throw If the nodal connectivity of cells is not defined.
3813 * \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3814 * \throw If magnitude of \a vec is less than 1e-6.
3815 * \throw If the plane does not intersect any 3D cell of \a this mesh.
3816 * \throw If \a this includes quadratic cells.
3818 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3820 checkFullyDefined();
3821 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3822 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3823 MCAuto<DataArrayInt> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3824 if(candidates->empty())
3825 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3826 std::vector<int> nodes;
3827 DataArrayInt *cellIds1D=0;
3828 MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3829 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3830 MCAuto<DataArrayInt> desc1=DataArrayInt::New(),desc2=DataArrayInt::New();
3831 MCAuto<DataArrayInt> descIndx1=DataArrayInt::New(),descIndx2=DataArrayInt::New();
3832 MCAuto<DataArrayInt> revDesc1=DataArrayInt::New(),revDesc2=DataArrayInt::New();
3833 MCAuto<DataArrayInt> revDescIndx1=DataArrayInt::New(),revDescIndx2=DataArrayInt::New();
3834 MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3835 revDesc2=0; revDescIndx2=0;
3836 MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3837 revDesc1=0; revDescIndx1=0;
3838 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3839 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3841 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3842 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3844 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3845 std::vector< std::pair<int,int> > cut3DSurf(mDesc2->getNumberOfCells());
3846 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3847 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3848 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3849 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New());
3850 connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3851 subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3852 if(cellIds2->empty())
3853 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3854 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3855 ret->setCoords(mDesc1->getCoords());
3856 ret->setConnectivity(conn,connI,true);
3857 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3862 * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3863 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
3864 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3866 * \param [in] origin - 3 components of a point defining location of the plane.
3867 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3868 * must be greater than 1e-6.
3869 * \param [in] eps - half-thickness of the plane.
3870 * \param [out] cellIds - a new instance of DataArrayInt holding ids of faces
3871 * producing correspondent segments. The caller is to delete this array
3872 * using decrRef() as it is no more needed.
3873 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3874 * mesh in 3D space. This mesh does not share the node coordinates array with
3875 * \a this mesh. The caller is to delete this mesh using decrRef() as it is
3877 * \throw If the coordinates array is not set.
3878 * \throw If the nodal connectivity of cells is not defined.
3879 * \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3880 * \throw If magnitude of \a vec is less than 1e-6.
3881 * \throw If the plane does not intersect any 2D cell of \a this mesh.
3882 * \throw If \a this includes quadratic cells.
3884 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3886 checkFullyDefined();
3887 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3888 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3889 MCAuto<DataArrayInt> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3890 if(candidates->empty())
3891 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3892 std::vector<int> nodes;
3893 DataArrayInt *cellIds1D=0;
3894 MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3895 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3896 MCAuto<DataArrayInt> desc1=DataArrayInt::New();
3897 MCAuto<DataArrayInt> descIndx1=DataArrayInt::New();
3898 MCAuto<DataArrayInt> revDesc1=DataArrayInt::New();
3899 MCAuto<DataArrayInt> revDescIndx1=DataArrayInt::New();
3900 MCAuto<MEDCouplingUMesh> mDesc1=subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3901 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3902 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3904 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3905 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3907 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3908 int ncellsSub=subMesh->getNumberOfCells();
3909 std::vector< std::pair<int,int> > cut3DSurf(ncellsSub);
3910 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3911 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3912 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3913 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New()); connI->pushBackSilent(0);
3915 const int *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3916 const int *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3917 for(int i=0;i<ncellsSub;i++)
3919 if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3921 if(cut3DSurf[i].first!=-2)
3923 conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3924 connI->pushBackSilent(conn->getNumberOfTuples());
3925 cellIds2->pushBackSilent(i);
3929 int cellId3DSurf=cut3DSurf[i].second;
3930 int offset=nodalI[cellId3DSurf]+1;
3931 int nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3932 for(int j=0;j<nbOfEdges;j++)
3934 conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3935 connI->pushBackSilent(conn->getNumberOfTuples());
3936 cellIds2->pushBackSilent(cellId3DSurf);
3941 if(cellIds2->empty())
3942 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3943 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3944 ret->setCoords(mDesc1->getCoords());
3945 ret->setConnectivity(conn,connI,true);
3946 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3951 * Finds cells whose bounding boxes intersect a given plane.
3952 * \param [in] origin - 3 components of a point defining location of the plane.
3953 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3954 * must be greater than 1e-6.
3955 * \param [in] eps - half-thickness of the plane.
3956 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of the found
3957 * cells. The caller is to delete this array using decrRef() as it is no more
3959 * \throw If the coordinates array is not set.
3960 * \throw If the nodal connectivity of cells is not defined.
3961 * \throw If \a this->getSpaceDimension() != 3.
3962 * \throw If magnitude of \a vec is less than 1e-6.
3963 * \sa buildSlice3D()
3965 DataArrayInt *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
3967 checkFullyDefined();
3968 if(getSpaceDimension()!=3)
3969 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
3970 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
3972 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
3974 vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
3975 double angle=acos(vec[2]/normm);
3976 MCAuto<DataArrayInt> cellIds;
3980 MCAuto<DataArrayDouble> coo=_coords->deepCopy();
3981 double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
3982 if(normm2/normm>1e-6)
3983 MEDCouplingPointSet::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer());
3984 MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
3986 mw->getBoundingBox(bbox);
3987 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3988 cellIds=mw->getCellsInBoundingBox(bbox,eps);
3992 getBoundingBox(bbox);
3993 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3994 cellIds=getCellsInBoundingBox(bbox,eps);
3996 return cellIds.retn();
4000 * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
4001 * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
4002 * No consideration of coordinate is done by this method.
4003 * 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)
4004 * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be usefull.
4006 bool MEDCouplingUMesh::isContiguous1D() const
4008 if(getMeshDimension()!=1)
4009 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
4010 int nbCells=getNumberOfCells();
4012 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
4013 const int *connI=_nodal_connec_index->getConstPointer();
4014 const int *conn=_nodal_connec->getConstPointer();
4015 int ref=conn[connI[0]+2];
4016 for(int i=1;i<nbCells;i++)
4018 if(conn[connI[i]+1]!=ref)
4020 ref=conn[connI[i]+2];
4026 * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
4027 * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
4028 * \param pt reference point of the line
4029 * \param v normalized director vector of the line
4030 * \param eps max precision before throwing an exception
4031 * \param res output of size this->getNumberOfCells
4033 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
4035 if(getMeshDimension()!=1)
4036 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
4037 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
4038 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
4039 if(getSpaceDimension()!=3)
4040 throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
4041 MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
4042 const double *fPtr=f->getArray()->getConstPointer();
4044 for(int i=0;i<getNumberOfCells();i++)
4046 const double *tmp1=fPtr+3*i;
4047 tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
4048 tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
4049 tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
4050 double n1=INTERP_KERNEL::norm<3>(tmp);
4051 n1/=INTERP_KERNEL::norm<3>(tmp1);
4053 throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
4055 const double *coo=getCoords()->getConstPointer();
4056 for(int i=0;i<getNumberOfNodes();i++)
4058 std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
4059 std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
4060 res[i]=std::accumulate(tmp,tmp+3,0.);
4065 * 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.
4066 * \a this is expected to be a mesh so that its space dimension is equal to its
4067 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4068 * 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).
4070 * 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
4071 * 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).
4072 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4074 * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
4075 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4077 * \param [in] ptBg the start pointer (included) of the coordinates of the point
4078 * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
4079 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4080 * \return the positive value of the distance.
4081 * \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
4083 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
4085 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, int& cellId) const
4087 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4088 if(meshDim!=spaceDim-1)
4089 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
4090 if(meshDim!=2 && meshDim!=1)
4091 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
4092 checkFullyDefined();
4093 if((int)std::distance(ptBg,ptEnd)!=spaceDim)
4094 { std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoint : input point has to have dimension equal to the space dimension of this (" << spaceDim << ") !"; throw INTERP_KERNEL::Exception(oss.str().c_str()); }
4095 DataArrayInt *ret1=0;
4096 MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,C_DEALLOC,1,spaceDim);
4097 MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
4098 MCAuto<DataArrayInt> ret1Safe(ret1);
4099 cellId=*ret1Safe->begin();
4100 return *ret0->begin();
4104 * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
4105 * to \a this and the first \a cellId in \a this corresponding to the returned distance.
4106 * 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
4107 * 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).
4108 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4110 * \a this is expected to be a mesh so that its space dimension is equal to its
4111 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4112 * 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).
4114 * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
4115 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4117 * \param [in] pts the list of points in which each tuple represents a point
4118 * \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.
4119 * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
4120 * \throw if number of components of \a pts is not equal to the space dimension.
4121 * \throw if mesh dimension of \a this is not equal to space dimension - 1.
4122 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
4124 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayInt *& cellIds) const
4127 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
4128 pts->checkAllocated();
4129 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4130 if(meshDim!=spaceDim-1)
4131 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
4132 if(meshDim!=2 && meshDim!=1)
4133 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
4134 if(pts->getNumberOfComponents()!=spaceDim)
4136 std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
4137 throw INTERP_KERNEL::Exception(oss.str().c_str());
4139 checkFullyDefined();
4140 int nbCells=getNumberOfCells();
4142 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
4143 int nbOfPts=pts->getNumberOfTuples();
4144 MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
4145 MCAuto<DataArrayInt> ret1=DataArrayInt::New(); ret1->alloc(nbOfPts,1);
4146 const int *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
4147 double *ret0Ptr=ret0->getPointer(); int *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
4148 MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
4149 const double *bbox(bboxArr->begin());
4154 BBTreeDst<3> myTree(bbox,0,0,nbCells);
4155 for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
4157 double x=std::numeric_limits<double>::max();
4158 std::vector<int> elems;
4159 myTree.getMinDistanceOfMax(ptsPtr,x);
4160 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4161 DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4167 BBTreeDst<2> myTree(bbox,0,0,nbCells);
4168 for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4170 double x=std::numeric_limits<double>::max();
4171 std::vector<int> elems;
4172 myTree.getMinDistanceOfMax(ptsPtr,x);
4173 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4174 DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4179 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4181 cellIds=ret1.retn();
4188 * \param [in] pt the start pointer (included) of the coordinates of the point
4189 * \param [in] cellIdsBg the start pointer (included) of cellIds
4190 * \param [in] cellIdsEnd the end pointer (excluded) of cellIds
4191 * \param [in] nc nodal connectivity
4192 * \param [in] ncI nodal connectivity index
4193 * \param [in,out] ret0 the min distance between \a this and the external input point
4194 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4195 * \sa MEDCouplingUMesh::distanceToPoint, MEDCouplingUMesh::distanceToPoints
4197 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)
4200 ret0=std::numeric_limits<double>::max();
4201 for(const int *zeCell=cellIdsBg;zeCell!=cellIdsEnd;zeCell++)
4203 switch((INTERP_KERNEL::NormalizedCellType)nc[ncI[*zeCell]])
4205 case INTERP_KERNEL::NORM_TRI3:
4207 double tmp=INTERP_KERNEL::DistanceFromPtToTriInSpaceDim3(pt,coords+3*nc[ncI[*zeCell]+1],coords+3*nc[ncI[*zeCell]+2],coords+3*nc[ncI[*zeCell]+3]);
4209 { ret0=tmp; cellId=*zeCell; }
4212 case INTERP_KERNEL::NORM_QUAD4:
4213 case INTERP_KERNEL::NORM_POLYGON:
4215 double tmp=INTERP_KERNEL::DistanceFromPtToPolygonInSpaceDim3(pt,nc+ncI[*zeCell]+1,nc+ncI[*zeCell+1],coords);
4217 { ret0=tmp; cellId=*zeCell; }
4221 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint3DSurfAlg : not managed cell type ! Supporting TRI3, QUAD4 and POLYGON !");
4227 * \param [in] pt the start pointer (included) of the coordinates of the point
4228 * \param [in] cellIdsBg the start pointer (included) of cellIds
4229 * \param [in] cellIdsEnd the end pointer (excluded) of cellIds
4230 * \param [in] nc nodal connectivity
4231 * \param [in] ncI nodal connectivity index
4232 * \param [in,out] ret0 the min distance between \a this and the external input point
4233 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4234 * \sa MEDCouplingUMesh::distanceToPoint, MEDCouplingUMesh::distanceToPoints
4236 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)
4239 ret0=std::numeric_limits<double>::max();
4240 for(const int *zeCell=cellIdsBg;zeCell!=cellIdsEnd;zeCell++)
4242 switch((INTERP_KERNEL::NormalizedCellType)nc[ncI[*zeCell]])
4244 case INTERP_KERNEL::NORM_SEG2:
4246 std::size_t uselessEntry=0;
4247 double tmp=INTERP_KERNEL::SquareDistanceFromPtToSegInSpaceDim2(pt,coords+2*nc[ncI[*zeCell]+1],coords+2*nc[ncI[*zeCell]+2],uselessEntry);
4250 { ret0=tmp; cellId=*zeCell; }
4254 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint2DCurveAlg : not managed cell type ! Supporting SEG2 !");
4261 * Finds cells in contact with a ball (i.e. a point with precision).
4262 * 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.
4263 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4265 * \warning This method is suitable if the caller intends to evaluate only one
4266 * point, for more points getCellsContainingPoints() is recommended as it is
4268 * \param [in] pos - array of coordinates of the ball central point.
4269 * \param [in] eps - ball radius.
4270 * \return int - a smallest id of cells being in contact with the ball, -1 in case
4271 * if there are no such cells.
4272 * \throw If the coordinates array is not set.
4273 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4275 int MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4277 std::vector<int> elts;
4278 getCellsContainingPoint(pos,eps,elts);
4281 return elts.front();
4285 * Finds cells in contact with a ball (i.e. a point with precision).
4286 * 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.
4287 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4288 * \warning This method is suitable if the caller intends to evaluate only one
4289 * point, for more points getCellsContainingPoints() is recommended as it is
4291 * \param [in] pos - array of coordinates of the ball central point.
4292 * \param [in] eps - ball radius.
4293 * \param [out] elts - vector returning ids of the found cells. It is cleared
4294 * before inserting ids.
4295 * \throw If the coordinates array is not set.
4296 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4298 * \if ENABLE_EXAMPLES
4299 * \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4300 * \ref py_mcumesh_getCellsContainingPoint "Here is a Python example".
4303 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<int>& elts) const
4305 MCAuto<DataArrayInt> eltsUg,eltsIndexUg;
4306 getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4307 elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4312 namespace MEDCoupling
4314 template<const int SPACEDIMM>
4318 static const int MY_SPACEDIM=SPACEDIMM;
4319 static const int MY_MESHDIM=8;
4320 typedef int MyConnType;
4321 static const INTERP_KERNEL::NumberingPolicy My_numPol=INTERP_KERNEL::ALL_C_MODE;
4323 // useless, but for windows compilation ...
4324 const double* getCoordinatesPtr() const { return 0; }
4325 const int* getConnectivityPtr() const { return 0; }
4326 const int* getConnectivityIndexPtr() const { return 0; }
4327 INTERP_KERNEL::NormalizedCellType getTypeOfElement(int) const { return (INTERP_KERNEL::NormalizedCellType)0; }
4331 INTERP_KERNEL::Edge *MEDCouplingUMeshBuildQPFromEdge2(INTERP_KERNEL::NormalizedCellType typ, const int *bg, const double *coords2D, std::map< MCAuto<INTERP_KERNEL::Node>,int>& m)
4333 INTERP_KERNEL::Edge *ret(0);
4334 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]));
4335 m[n0]=bg[0]; m[n1]=bg[1];
4338 case INTERP_KERNEL::NORM_SEG2:
4340 ret=new INTERP_KERNEL::EdgeLin(n0,n1);
4343 case INTERP_KERNEL::NORM_SEG3:
4345 INTERP_KERNEL::Node *n2(new INTERP_KERNEL::Node(coords2D[2*bg[2]],coords2D[2*bg[2]+1])); m[n2]=bg[2];
4346 INTERP_KERNEL::EdgeLin *e1(new INTERP_KERNEL::EdgeLin(n0,n2)),*e2(new INTERP_KERNEL::EdgeLin(n2,n1));
4347 INTERP_KERNEL::SegSegIntersector inters(*e1,*e2);
4348 // is the SEG3 degenerated, and thus can be reduced to a SEG2?
4349 bool colinearity(inters.areColinears());
4350 delete e1; delete e2;
4352 { ret=new INTERP_KERNEL::EdgeLin(n0,n1); }
4354 { ret=new INTERP_KERNEL::EdgeArcCircle(n0,n2,n1); }
4358 throw INTERP_KERNEL::Exception("MEDCouplingUMeshBuildQPFromEdge2 : Expecting a mesh with spaceDim==2 and meshDim==1 !");
4363 INTERP_KERNEL::Edge *MEDCouplingUMeshBuildQPFromEdge(INTERP_KERNEL::NormalizedCellType typ, std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >& mapp2, const int *bg)
4365 INTERP_KERNEL::Edge *ret=0;
4368 case INTERP_KERNEL::NORM_SEG2:
4370 ret=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[1]].first);
4373 case INTERP_KERNEL::NORM_SEG3:
4375 INTERP_KERNEL::EdgeLin *e1=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[2]].first);
4376 INTERP_KERNEL::EdgeLin *e2=new INTERP_KERNEL::EdgeLin(mapp2[bg[2]].first,mapp2[bg[1]].first);
4377 INTERP_KERNEL::SegSegIntersector inters(*e1,*e2);
4378 // is the SEG3 degenerated, and thus can be reduced to a SEG2?
4379 bool colinearity=inters.areColinears();
4380 delete e1; delete e2;
4382 ret=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[1]].first);
4384 ret=new INTERP_KERNEL::EdgeArcCircle(mapp2[bg[0]].first,mapp2[bg[2]].first,mapp2[bg[1]].first);
4385 mapp2[bg[2]].second=false;
4389 throw INTERP_KERNEL::Exception("MEDCouplingUMeshBuildQPFromEdge : Expecting a mesh with spaceDim==2 and meshDim==1 !");
4395 * This method creates a sub mesh in Geometric2D DS. The sub mesh is composed by the sub set of cells in 'candidates' taken from
4396 * the global mesh 'mDesc'.
4397 * The input mesh 'mDesc' must be so that mDim==1 and spaceDim==2.
4398 * 'mapp' returns a mapping between local numbering in submesh (represented by a Node*) and the global node numbering in 'mDesc'.
4400 INTERP_KERNEL::QuadraticPolygon *MEDCouplingUMeshBuildQPFromMesh(const MEDCouplingUMesh *mDesc, const std::vector<int>& candidates,
4401 std::map<INTERP_KERNEL::Node *,int>& mapp)
4404 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.
4405 const double *coo=mDesc->getCoords()->getConstPointer();
4406 const int *c=mDesc->getNodalConnectivity()->getConstPointer();
4407 const int *cI=mDesc->getNodalConnectivityIndex()->getConstPointer();
4409 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
4410 s.insert(c+cI[*it]+1,c+cI[(*it)+1]);
4411 for(std::set<int>::const_iterator it2=s.begin();it2!=s.end();it2++)
4413 INTERP_KERNEL::Node *n=new INTERP_KERNEL::Node(coo[2*(*it2)],coo[2*(*it2)+1]);
4414 mapp2[*it2]=std::pair<INTERP_KERNEL::Node *,bool>(n,true);
4416 INTERP_KERNEL::QuadraticPolygon *ret=new INTERP_KERNEL::QuadraticPolygon;
4417 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
4419 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[*it]];
4420 ret->pushBack(MEDCouplingUMeshBuildQPFromEdge(typ,mapp2,c+cI[*it]+1));
4422 for(std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >::const_iterator it2=mapp2.begin();it2!=mapp2.end();it2++)
4424 if((*it2).second.second)
4425 mapp[(*it2).second.first]=(*it2).first;
4426 ((*it2).second.first)->decrRef();
4431 INTERP_KERNEL::Node *MEDCouplingUMeshBuildQPNode(int nodeId, const double *coo1, int offset1, const double *coo2, int offset2, const std::vector<double>& addCoo)
4435 int locId=nodeId-offset2;
4436 return new INTERP_KERNEL::Node(addCoo[2*locId],addCoo[2*locId+1]);
4440 int locId=nodeId-offset1;
4441 return new INTERP_KERNEL::Node(coo2[2*locId],coo2[2*locId+1]);
4443 return new INTERP_KERNEL::Node(coo1[2*nodeId],coo1[2*nodeId+1]);
4447 * Construct a mapping between set of Nodes and the standart MEDCoupling connectivity format (c, cI).
4449 void MEDCouplingUMeshBuildQPFromMesh3(const double *coo1, int offset1, const double *coo2, int offset2, const std::vector<double>& addCoo,
4450 const int *desc1Bg, const int *desc1End, const std::vector<std::vector<int> >& intesctEdges1,
4451 /*output*/std::map<INTERP_KERNEL::Node *,int>& mapp, std::map<int,INTERP_KERNEL::Node *>& mappRev)
4453 for(const int *desc1=desc1Bg;desc1!=desc1End;desc1++)
4455 int eltId1=abs(*desc1)-1;
4456 for(std::vector<int>::const_iterator it1=intesctEdges1[eltId1].begin();it1!=intesctEdges1[eltId1].end();it1++)
4458 std::map<int,INTERP_KERNEL::Node *>::const_iterator it=mappRev.find(*it1);
4459 if(it==mappRev.end())
4461 INTERP_KERNEL::Node *node=MEDCouplingUMeshBuildQPNode(*it1,coo1,offset1,coo2,offset2,addCoo);
4472 template<int SPACEDIM>
4473 void MEDCouplingUMesh::getCellsContainingPointsAlg(const double *coords, const double *pos, int nbOfPoints,
4474 double eps, MCAuto<DataArrayInt>& elts, MCAuto<DataArrayInt>& eltsIndex) const
4476 elts=DataArrayInt::New(); eltsIndex=DataArrayInt::New(); eltsIndex->alloc(nbOfPoints+1,1); eltsIndex->setIJ(0,0,0); elts->alloc(0,1);
4477 int *eltsIndexPtr(eltsIndex->getPointer());
4478 MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree(eps));
4479 const double *bbox(bboxArr->begin());
4480 int nbOfCells=getNumberOfCells();
4481 const int *conn=_nodal_connec->getConstPointer();
4482 const int *connI=_nodal_connec_index->getConstPointer();
4483 double bb[2*SPACEDIM];
4484 BBTree<SPACEDIM,int> myTree(&bbox[0],0,0,nbOfCells,-eps);
4485 for(int i=0;i<nbOfPoints;i++)
4487 eltsIndexPtr[i+1]=eltsIndexPtr[i];
4488 for(int j=0;j<SPACEDIM;j++)
4490 bb[2*j]=pos[SPACEDIM*i+j];
4491 bb[2*j+1]=pos[SPACEDIM*i+j];
4493 std::vector<int> candidates;
4494 myTree.getIntersectingElems(bb,candidates);
4495 for(std::vector<int>::const_iterator iter=candidates.begin();iter!=candidates.end();iter++)
4497 int sz(connI[(*iter)+1]-connI[*iter]-1);
4498 INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[connI[*iter]]);
4500 if(ct!=INTERP_KERNEL::NORM_POLYGON && ct!=INTERP_KERNEL::NORM_QPOLYG)
4501 status=INTERP_KERNEL::PointLocatorAlgos<DummyClsMCUG<SPACEDIM> >::isElementContainsPoint(pos+i*SPACEDIM,ct,coords,conn+connI[*iter]+1,sz,eps);
4505 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPointsAlg : not implemented yet for POLYGON and QPOLYGON in spaceDim 3 !");
4506 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
4507 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
4508 std::vector<INTERP_KERNEL::Node *> nodes(sz);
4509 INTERP_KERNEL::QuadraticPolygon *pol(0);
4510 for(int j=0;j<sz;j++)
4512 int nodeId(conn[connI[*iter]+1+j]);
4513 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*SPACEDIM],coords[nodeId*SPACEDIM+1]);
4515 if(!INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic())
4516 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
4518 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
4519 INTERP_KERNEL::Node *n(new INTERP_KERNEL::Node(pos[i*SPACEDIM],pos[i*SPACEDIM+1]));
4520 double a(0.),b(0.),c(0.);
4521 a=pol->normalizeMe(b,c); n->applySimilarity(b,c,a);
4522 status=pol->isInOrOut2(n);
4523 delete pol; n->decrRef();
4527 eltsIndexPtr[i+1]++;
4528 elts->pushBackSilent(*iter);
4534 * Finds cells in contact with several balls (i.e. points with precision).
4535 * This method is an extension of getCellContainingPoint() and
4536 * getCellsContainingPoint() for the case of multiple points.
4537 * 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.
4538 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4539 * \param [in] pos - an array of coordinates of points in full interlace mode :
4540 * X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4541 * this->getSpaceDimension() * \a nbOfPoints
4542 * \param [in] nbOfPoints - number of points to locate within \a this mesh.
4543 * \param [in] eps - radius of balls (i.e. the precision).
4544 * \param [out] elts - vector returning ids of found cells.
4545 * \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4546 * dividing cell ids in \a elts into groups each referring to one
4547 * point. Its every element (except the last one) is an index pointing to the
4548 * first id of a group of cells. For example cells in contact with the *i*-th
4549 * point are described by following range of indices:
4550 * [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4551 * \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4552 * Number of cells in contact with the *i*-th point is
4553 * \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4554 * \throw If the coordinates array is not set.
4555 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4557 * \if ENABLE_EXAMPLES
4558 * \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4559 * \ref py_mcumesh_getCellsContainingPoints "Here is a Python example".
4562 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, int nbOfPoints, double eps,
4563 MCAuto<DataArrayInt>& elts, MCAuto<DataArrayInt>& eltsIndex) const
4565 int spaceDim=getSpaceDimension();
4566 int mDim=getMeshDimension();
4571 const double *coords=_coords->getConstPointer();
4572 getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4579 throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4581 else if(spaceDim==2)
4585 const double *coords=_coords->getConstPointer();
4586 getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4589 throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4591 else if(spaceDim==1)
4595 const double *coords=_coords->getConstPointer();
4596 getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4599 throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4602 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4606 * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4607 * least two its edges intersect each other anywhere except their extremities. An
4608 * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4609 * \param [in,out] cells - a vector returning ids of the found cells. It is not
4610 * cleared before filling in.
4611 * \param [in] eps - precision.
4612 * \throw If \a this->getMeshDimension() != 2.
4613 * \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4615 void MEDCouplingUMesh::checkButterflyCells(std::vector<int>& cells, double eps) const
4617 const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4618 if(getMeshDimension()!=2)
4619 throw INTERP_KERNEL::Exception(msg);
4620 int spaceDim=getSpaceDimension();
4621 if(spaceDim!=2 && spaceDim!=3)
4622 throw INTERP_KERNEL::Exception(msg);
4623 const int *conn=_nodal_connec->getConstPointer();
4624 const int *connI=_nodal_connec_index->getConstPointer();
4625 int nbOfCells=getNumberOfCells();
4626 std::vector<double> cell2DinS2;
4627 for(int i=0;i<nbOfCells;i++)
4629 int offset=connI[i];
4630 int nbOfNodesForCell=connI[i+1]-offset-1;
4631 if(nbOfNodesForCell<=3)
4633 bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4634 project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4635 if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4642 * This method is typically requested to unbutterfly 2D linear cells in \b this.
4644 * 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.
4645 * 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.
4647 * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4648 * This convex envelop is computed using Jarvis march algorithm.
4649 * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4650 * 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)
4651 * 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.
4653 * \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.
4654 * \sa MEDCouplingUMesh::colinearize2D
4656 DataArrayInt *MEDCouplingUMesh::convexEnvelop2D()
4658 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4659 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D works only for meshDim=2 and spaceDim=2 !");
4660 checkFullyDefined();
4661 const double *coords=getCoords()->getConstPointer();
4662 int nbOfCells=getNumberOfCells();
4663 MCAuto<DataArrayInt> nodalConnecIndexOut=DataArrayInt::New();
4664 nodalConnecIndexOut->alloc(nbOfCells+1,1);
4665 MCAuto<DataArrayInt> nodalConnecOut(DataArrayInt::New());
4666 int *workIndexOut=nodalConnecIndexOut->getPointer();
4668 const int *nodalConnecIn=_nodal_connec->getConstPointer();
4669 const int *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4670 std::set<INTERP_KERNEL::NormalizedCellType> types;
4671 MCAuto<DataArrayInt> isChanged(DataArrayInt::New());
4672 isChanged->alloc(0,1);
4673 for(int i=0;i<nbOfCells;i++,workIndexOut++)
4675 int pos=nodalConnecOut->getNumberOfTuples();
4676 if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4677 isChanged->pushBackSilent(i);
4678 types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4679 workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4681 if(isChanged->empty())
4683 setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4685 return isChanged.retn();
4689 * This method is \b NOT const because it can modify \a this.
4690 * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4691 * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4692 * \param policy specifies the type of extrusion chosen:
4693 * - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4694 * will be repeated to build each level
4695 * - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4696 * 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
4697 * 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
4699 * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4701 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4703 checkFullyDefined();
4704 mesh1D->checkFullyDefined();
4705 if(!mesh1D->isContiguous1D())
4706 throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4707 if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4708 throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4709 if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4710 throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4711 if(mesh1D->getMeshDimension()!=1)
4712 throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4714 if(isPresenceOfQuadratic())
4716 if(mesh1D->isFullyQuadratic())
4719 throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4721 int oldNbOfNodes(getNumberOfNodes());
4722 MCAuto<DataArrayDouble> newCoords;
4727 newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4732 newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4736 throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4738 setCoords(newCoords);
4739 MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4745 * This method works on a 3D curve linear mesh that is to say (meshDim==1 and spaceDim==3).
4746 * If it is not the case an exception will be thrown.
4747 * This method is non const because the coordinate of \a this can be appended with some new points issued from
4748 * intersection of plane defined by ('origin','vec').
4749 * This method has one in/out parameter : 'cut3DCurve'.
4750 * Param 'cut3DCurve' is expected to be of size 'this->getNumberOfCells()'. For each i in [0,'this->getNumberOfCells()')
4751 * if cut3DCurve[i]==-2, it means that for cell #i in \a this nothing has been detected previously.
4752 * if cut3DCurve[i]==-1, it means that cell#i has been already detected to be fully part of plane defined by ('origin','vec').
4753 * This method will throw an exception if \a this contains a non linear segment.
4755 void MEDCouplingUMesh::split3DCurveWithPlane(const double *origin, const double *vec, double eps, std::vector<int>& cut3DCurve)
4757 checkFullyDefined();
4758 if(getMeshDimension()!=1 || getSpaceDimension()!=3)
4759 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane works on umeshes with meshdim equal to 1 and spaceDim equal to 3 !");
4760 int ncells=getNumberOfCells();
4761 int nnodes=getNumberOfNodes();
4762 double vec2[3],vec3[3],vec4[3];
4763 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
4765 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
4766 vec2[0]=vec[0]/normm; vec2[1]=vec[1]/normm; vec2[2]=vec[2]/normm;
4767 const int *conn=_nodal_connec->getConstPointer();
4768 const int *connI=_nodal_connec_index->getConstPointer();
4769 const double *coo=_coords->getConstPointer();
4770 std::vector<double> addCoo;
4771 for(int i=0;i<ncells;i++)
4773 if(conn[connI[i]]==(int)INTERP_KERNEL::NORM_SEG2)
4775 if(cut3DCurve[i]==-2)
4777 int st=conn[connI[i]+1],endd=conn[connI[i]+2];
4778 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];
4779 double normm2=sqrt(vec3[0]*vec3[0]+vec3[1]*vec3[1]+vec3[2]*vec3[2]);
4780 double colin=std::abs((vec3[0]*vec2[0]+vec3[1]*vec2[1]+vec3[2]*vec2[2])/normm2);
4781 if(colin>eps)//if colin<=eps -> current SEG2 is colinear to the input plane
4783 const double *st2=coo+3*st;
4784 vec4[0]=st2[0]-origin[0]; vec4[1]=st2[1]-origin[1]; vec4[2]=st2[2]-origin[2];
4785 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]));
4786 if(pos>eps && pos<1-eps)
4788 int nNode=((int)addCoo.size())/3;
4789 vec4[0]=st2[0]+pos*vec3[0]; vec4[1]=st2[1]+pos*vec3[1]; vec4[2]=st2[2]+pos*vec3[2];
4790 addCoo.insert(addCoo.end(),vec4,vec4+3);
4791 cut3DCurve[i]=nnodes+nNode;
4797 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane : this method is only available for linear cell (NORM_SEG2) !");
4801 int newNbOfNodes=nnodes+((int)addCoo.size())/3;
4802 MCAuto<DataArrayDouble> coo2=DataArrayDouble::New();
4803 coo2->alloc(newNbOfNodes,3);
4804 double *tmp=coo2->getPointer();
4805 tmp=std::copy(_coords->begin(),_coords->end(),tmp);
4806 std::copy(addCoo.begin(),addCoo.end(),tmp);
4807 DataArrayDouble::SetArrayIn(coo2,_coords);
4812 * This method incarnates the policy 0 for MEDCouplingUMesh::buildExtrudedMesh method.
4813 * \param mesh1D is the input 1D mesh used for translation computation.
4814 * \return newCoords new coords filled by this method.
4816 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslation(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4818 int oldNbOfNodes=getNumberOfNodes();
4819 int nbOf1DCells=mesh1D->getNumberOfCells();
4820 int spaceDim=getSpaceDimension();
4821 DataArrayDouble *ret=DataArrayDouble::New();
4822 std::vector<bool> isQuads;
4823 int nbOfLevsInVec=isQuad?2*nbOf1DCells+1:nbOf1DCells+1;
4824 ret->alloc(oldNbOfNodes*nbOfLevsInVec,spaceDim);
4825 double *retPtr=ret->getPointer();
4826 const double *coords=getCoords()->getConstPointer();
4827 double *work=std::copy(coords,coords+spaceDim*oldNbOfNodes,retPtr);
4829 std::vector<double> c;
4833 for(int i=0;i<nbOf1DCells;i++)
4836 mesh1D->getNodeIdsOfCell(i,v);
4838 mesh1D->getCoordinatesOfNode(v[isQuad?2:1],c);
4839 mesh1D->getCoordinatesOfNode(v[0],c);
4840 std::transform(c.begin(),c.begin()+spaceDim,c.begin()+spaceDim,vec,std::minus<double>());
4841 for(int j=0;j<oldNbOfNodes;j++)
4842 work=std::transform(vec,vec+spaceDim,retPtr+spaceDim*(i*oldNbOfNodes+j),work,std::plus<double>());
4846 mesh1D->getCoordinatesOfNode(v[1],c);
4847 mesh1D->getCoordinatesOfNode(v[0],c);
4848 std::transform(c.begin(),c.begin()+spaceDim,c.begin()+spaceDim,vec,std::minus<double>());
4849 for(int j=0;j<oldNbOfNodes;j++)
4850 work=std::transform(vec,vec+spaceDim,retPtr+spaceDim*(i*oldNbOfNodes+j),work,std::plus<double>());
4853 ret->copyStringInfoFrom(*getCoords());
4858 * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4859 * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4860 * \return newCoords new coords filled by this method.
4862 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4864 if(mesh1D->getSpaceDimension()==2)
4865 return fillExtCoordsUsingTranslAndAutoRotation2D(mesh1D,isQuad);
4866 if(mesh1D->getSpaceDimension()==3)
4867 return fillExtCoordsUsingTranslAndAutoRotation3D(mesh1D,isQuad);
4868 throw INTERP_KERNEL::Exception("Not implemented rotation and translation alg. for spacedim other than 2 and 3 !");
4872 * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4873 * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4874 * \return newCoords new coords filled by this method.
4876 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4879 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D : not implemented for quadratic cells !");
4880 int oldNbOfNodes=getNumberOfNodes();
4881 int nbOf1DCells=mesh1D->getNumberOfCells();
4883 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D : impossible to detect any angle of rotation ! Change extrusion policy 1->0 !");
4884 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
4885 int nbOfLevsInVec=nbOf1DCells+1;
4886 ret->alloc(oldNbOfNodes*nbOfLevsInVec,2);
4887 double *retPtr=ret->getPointer();
4888 retPtr=std::copy(getCoords()->getConstPointer(),getCoords()->getConstPointer()+getCoords()->getNbOfElems(),retPtr);
4889 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
4890 MCAuto<DataArrayDouble> tmp2=getCoords()->deepCopy();
4891 tmp->setCoords(tmp2);
4892 const double *coo1D=mesh1D->getCoords()->getConstPointer();
4893 const int *conn1D=mesh1D->getNodalConnectivity()->getConstPointer();
4894 const int *connI1D=mesh1D->getNodalConnectivityIndex()->getConstPointer();
4895 for(int i=1;i<nbOfLevsInVec;i++)
4897 const double *begin=coo1D+2*conn1D[connI1D[i-1]+1];
4898 const double *end=coo1D+2*conn1D[connI1D[i-1]+2];
4899 const double *third=i+1<nbOfLevsInVec?coo1D+2*conn1D[connI1D[i]+2]:coo1D+2*conn1D[connI1D[i-2]+1];
4900 const double vec[2]={end[0]-begin[0],end[1]-begin[1]};
4901 tmp->translate(vec);
4902 double tmp3[2],radius,alpha,alpha0;
4903 const double *p0=i+1<nbOfLevsInVec?begin:third;
4904 const double *p1=i+1<nbOfLevsInVec?end:begin;
4905 const double *p2=i+1<nbOfLevsInVec?third:end;
4906 INTERP_KERNEL::EdgeArcCircle::GetArcOfCirclePassingThru(p0,p1,p2,tmp3,radius,alpha,alpha0);
4907 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]);
4908 double angle=acos(cosangle/(radius*radius));
4909 tmp->rotate(end,0,angle);
4910 retPtr=std::copy(tmp2->getConstPointer(),tmp2->getConstPointer()+tmp2->getNbOfElems(),retPtr);
4916 * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4917 * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4918 * \return newCoords new coords filled by this method.
4920 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4923 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D : not implemented for quadratic cells !");
4924 int oldNbOfNodes=getNumberOfNodes();
4925 int nbOf1DCells=mesh1D->getNumberOfCells();
4927 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D : impossible to detect any angle of rotation ! Change extrusion policy 1->0 !");
4928 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
4929 int nbOfLevsInVec=nbOf1DCells+1;
4930 ret->alloc(oldNbOfNodes*nbOfLevsInVec,3);
4931 double *retPtr=ret->getPointer();
4932 retPtr=std::copy(getCoords()->getConstPointer(),getCoords()->getConstPointer()+getCoords()->getNbOfElems(),retPtr);
4933 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
4934 MCAuto<DataArrayDouble> tmp2=getCoords()->deepCopy();
4935 tmp->setCoords(tmp2);
4936 const double *coo1D=mesh1D->getCoords()->getConstPointer();
4937 const int *conn1D=mesh1D->getNodalConnectivity()->getConstPointer();
4938 const int *connI1D=mesh1D->getNodalConnectivityIndex()->getConstPointer();
4939 for(int i=1;i<nbOfLevsInVec;i++)
4941 const double *begin=coo1D+3*conn1D[connI1D[i-1]+1];
4942 const double *end=coo1D+3*conn1D[connI1D[i-1]+2];
4943 const double *third=i+1<nbOfLevsInVec?coo1D+3*conn1D[connI1D[i]+2]:coo1D+3*conn1D[connI1D[i-2]+1];
4944 const double vec[3]={end[0]-begin[0],end[1]-begin[1],end[2]-begin[2]};
4945 tmp->translate(vec);
4946 double tmp3[2],radius,alpha,alpha0;
4947 const double *p0=i+1<nbOfLevsInVec?begin:third;
4948 const double *p1=i+1<nbOfLevsInVec?end:begin;
4949 const double *p2=i+1<nbOfLevsInVec?third:end;
4950 double vecPlane[3]={
4951 (p1[1]-p0[1])*(p2[2]-p1[2])-(p1[2]-p0[2])*(p2[1]-p1[1]),
4952 (p1[2]-p0[2])*(p2[0]-p1[0])-(p1[0]-p0[0])*(p2[2]-p1[2]),
4953 (p1[0]-p0[0])*(p2[1]-p1[1])-(p1[1]-p0[1])*(p2[0]-p1[0]),
4955 double norm=sqrt(vecPlane[0]*vecPlane[0]+vecPlane[1]*vecPlane[1]+vecPlane[2]*vecPlane[2]);
4958 vecPlane[0]/=norm; vecPlane[1]/=norm; vecPlane[2]/=norm;
4959 double norm2=sqrt(vecPlane[0]*vecPlane[0]+vecPlane[1]*vecPlane[1]);
4960 double vec2[2]={vecPlane[1]/norm2,-vecPlane[0]/norm2};
4962 double c2=cos(asin(s2));
4964 {vec2[0]*vec2[0]*(1-c2)+c2, vec2[0]*vec2[1]*(1-c2), vec2[1]*s2},
4965 {vec2[0]*vec2[1]*(1-c2), vec2[1]*vec2[1]*(1-c2)+c2, -vec2[0]*s2},
4966 {-vec2[1]*s2, vec2[0]*s2, c2}
4968 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]};
4969 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]};
4970 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]};
4971 INTERP_KERNEL::EdgeArcCircle::GetArcOfCirclePassingThru(p0r,p1r,p2r,tmp3,radius,alpha,alpha0);
4972 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]);
4973 double angle=acos(cosangle/(radius*radius));
4974 tmp->rotate(end,vecPlane,angle);
4976 retPtr=std::copy(tmp2->getConstPointer(),tmp2->getConstPointer()+tmp2->getNbOfElems(),retPtr);
4982 * This method is private because not easy to use for end user. This method is const contrary to
4983 * MEDCouplingUMesh::buildExtrudedMesh method because this->_coords are expected to contain
4984 * the coords sorted slice by slice.
4985 * \param isQuad specifies presence of quadratic cells.
4987 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMeshFromThisLowLev(int nbOfNodesOf1Lev, bool isQuad) const
4989 int nbOf1DCells(getNumberOfNodes()/nbOfNodesOf1Lev-1);
4990 int nbOf2DCells(getNumberOfCells());
4991 int nbOf3DCells(nbOf2DCells*nbOf1DCells);
4992 MEDCouplingUMesh *ret(MEDCouplingUMesh::New("Extruded",getMeshDimension()+1));
4993 const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
4994 MCAuto<DataArrayInt> newConn(DataArrayInt::New()),newConnI(DataArrayInt::New());
4995 newConnI->alloc(nbOf3DCells+1,1);
4996 int *newConnIPtr(newConnI->getPointer());
4998 std::vector<int> newc;
4999 for(int j=0;j<nbOf2DCells;j++)
5001 AppendExtrudedCell(conn+connI[j],conn+connI[j+1],nbOfNodesOf1Lev,isQuad,newc);
5002 *newConnIPtr++=(int)newc.size();
5004 newConn->alloc((int)(newc.size())*nbOf1DCells,1);
5005 int *newConnPtr(newConn->getPointer());
5006 int deltaPerLev(isQuad?2*nbOfNodesOf1Lev:nbOfNodesOf1Lev);
5007 newConnIPtr=newConnI->getPointer();
5008 for(int iz=0;iz<nbOf1DCells;iz++)
5011 std::transform(newConnIPtr+1,newConnIPtr+1+nbOf2DCells,newConnIPtr+1+iz*nbOf2DCells,std::bind2nd(std::plus<int>(),newConnIPtr[iz*nbOf2DCells]));
5012 const int *posOfTypeOfCell(newConnIPtr);
5013 for(std::vector<int>::const_iterator iter=newc.begin();iter!=newc.end();iter++,newConnPtr++)
5015 int icell((int)(iter-newc.begin()));//std::distance unfortunately cannot been called here in C++98
5016 if(icell!=*posOfTypeOfCell)
5019 *newConnPtr=(*iter)+iz*deltaPerLev;
5030 ret->setConnectivity(newConn,newConnI,true);
5031 ret->setCoords(getCoords());
5036 * Checks if \a this mesh is constituted by only quadratic cells.
5037 * \return bool - \c true if there are only quadratic cells in \a this mesh.
5038 * \throw If the coordinates array is not set.
5039 * \throw If the nodal connectivity of cells is not defined.
5041 bool MEDCouplingUMesh::isFullyQuadratic() const
5043 checkFullyDefined();
5045 int nbOfCells=getNumberOfCells();
5046 for(int i=0;i<nbOfCells && ret;i++)
5048 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5049 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5050 ret=cm.isQuadratic();
5056 * Checks if \a this mesh includes any quadratic cell.
5057 * \return bool - \c true if there is at least one quadratic cells in \a this mesh.
5058 * \throw If the coordinates array is not set.
5059 * \throw If the nodal connectivity of cells is not defined.
5061 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
5063 checkFullyDefined();
5065 int nbOfCells=getNumberOfCells();
5066 for(int i=0;i<nbOfCells && !ret;i++)
5068 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5069 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5070 ret=cm.isQuadratic();
5076 * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
5077 * this mesh, it remains unchanged.
5078 * \throw If the coordinates array is not set.
5079 * \throw If the nodal connectivity of cells is not defined.
5081 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
5083 checkFullyDefined();
5084 int nbOfCells=getNumberOfCells();
5086 const int *iciptr=_nodal_connec_index->getConstPointer();
5087 for(int i=0;i<nbOfCells;i++)
5089 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5090 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5091 if(cm.isQuadratic())
5093 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
5094 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
5095 if(!cml.isDynamic())
5096 delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
5098 delta+=(iciptr[i+1]-iciptr[i]-1)/2;
5103 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5104 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5105 const int *icptr=_nodal_connec->getConstPointer();
5106 newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
5107 newConnI->alloc(nbOfCells+1,1);
5108 int *ocptr=newConn->getPointer();
5109 int *ociptr=newConnI->getPointer();
5112 for(int i=0;i<nbOfCells;i++,ociptr++)
5114 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
5115 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5116 if(!cm.isQuadratic())
5118 _types.insert(type);
5119 ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
5120 ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
5124 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
5125 _types.insert(typel);
5126 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
5127 int newNbOfNodes=cml.getNumberOfNodes();
5129 newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
5130 *ocptr++=(int)typel;
5131 ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
5132 ociptr[1]=ociptr[0]+newNbOfNodes+1;
5135 setConnectivity(newConn,newConnI,false);
5139 * This method converts all linear cell in \a this to quadratic one.
5140 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
5141 * 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)
5142 * 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.
5143 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
5144 * end of the existing coordinates.
5146 * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
5147 * corresponding quadratic cells. 1 is those creating the 'most' complex.
5148 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5150 * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
5152 * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
5154 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
5156 DataArrayInt *conn=0,*connI=0;
5157 DataArrayDouble *coords=0;
5158 std::set<INTERP_KERNEL::NormalizedCellType> types;
5159 checkFullyDefined();
5160 MCAuto<DataArrayInt> ret,connSafe,connISafe;
5161 MCAuto<DataArrayDouble> coordsSafe;
5162 int meshDim=getMeshDimension();
5163 switch(conversionType)
5169 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
5170 connSafe=conn; connISafe=connI; coordsSafe=coords;
5173 ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
5174 connSafe=conn; connISafe=connI; coordsSafe=coords;
5177 ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
5178 connSafe=conn; connISafe=connI; coordsSafe=coords;
5181 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
5189 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
5190 connSafe=conn; connISafe=connI; coordsSafe=coords;
5193 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
5194 connSafe=conn; connISafe=connI; coordsSafe=coords;
5197 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
5198 connSafe=conn; connISafe=connI; coordsSafe=coords;
5201 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
5206 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
5208 setConnectivity(connSafe,connISafe,false);
5210 setCoords(coordsSafe);
5215 * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
5216 * so that the number of cells remains the same. Quadratic faces are converted to
5217 * polygons. This method works only for 2D meshes in
5218 * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
5219 * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
5220 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5221 * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
5222 * a polylinized edge constituting the input polygon.
5223 * \throw If the coordinates array is not set.
5224 * \throw If the nodal connectivity of cells is not defined.
5225 * \throw If \a this->getMeshDimension() != 2.
5226 * \throw If \a this->getSpaceDimension() != 2.
5228 void MEDCouplingUMesh::tessellate2D(double eps)
5230 int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
5232 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
5236 return tessellate2DCurveInternal(eps);
5238 return tessellate2DInternal(eps);
5240 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
5244 * Tessellates \a this 1D mesh in 2D space by dividing not straight quadratic edges.
5245 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5246 * \param [in] eps - specifies the maximal angle (in radian) between 2 sub-edges of
5247 * a sub-divided edge.
5248 * \throw If the coordinates array is not set.
5249 * \throw If the nodal connectivity of cells is not defined.
5250 * \throw If \a this->getMeshDimension() != 1.
5251 * \throw If \a this->getSpaceDimension() != 2.
5256 * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
5257 * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
5258 * The nodes to be added in those 2D cells are defined by the pair of \a nodeIdsToAdd and \a nodeIdsIndexToAdd.
5259 * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
5260 * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
5261 * This method can be seen as the opposite method of colinearize2D.
5262 * 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
5263 * to avoid to modify the numbering of existing nodes.
5265 * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
5266 * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
5267 * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
5268 * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
5269 * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
5270 * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
5271 * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
5273 * \sa buildDescendingConnectivity2
5275 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayInt *nodeIdsToAdd, const DataArrayInt *nodeIdsIndexToAdd, const DataArrayInt *edgeIdsToBeSplit,
5276 const MEDCouplingUMesh *mesh1Desc, const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *revDesc, const DataArrayInt *revDescI)
5278 if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
5279 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
5280 nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
5281 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
5282 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
5283 if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
5284 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
5285 //DataArrayInt *out0(0),*outi0(0);
5286 //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
5287 //MCAuto<DataArrayInt> out0s(out0),outi0s(outi0);
5288 //out0s=out0s->buildUnique(); out0s->sort(true);
5293 * Implementes \a conversionType 0 for meshes with meshDim = 1, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5294 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5295 * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5297 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic1D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5299 MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5300 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5301 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5302 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5303 int nbOfCells=getNumberOfCells();
5304 int nbOfNodes=getNumberOfNodes();
5305 const int *cPtr=_nodal_connec->getConstPointer();
5306 const int *icPtr=_nodal_connec_index->getConstPointer();
5307 int lastVal=0,offset=nbOfNodes;
5308 for(int i=0;i<nbOfCells;i++,icPtr++)
5310 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5311 if(type==INTERP_KERNEL::NORM_SEG2)
5313 types.insert(INTERP_KERNEL::NORM_SEG3);
5314 newConn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG3);
5315 newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[0]+3);
5316 newConn->pushBackSilent(offset++);
5318 newConnI->pushBackSilent(lastVal);
5319 ret->pushBackSilent(i);
5324 lastVal+=(icPtr[1]-icPtr[0]);
5325 newConnI->pushBackSilent(lastVal);
5326 newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5329 MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5330 coords=DataArrayDouble::Aggregate(getCoords(),tmp); conn=newConn.retn(); connI=newConnI.retn();
5334 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
5336 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5337 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5338 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5340 const int *descPtr(desc->begin()),*descIPtr(descI->begin());
5341 DataArrayInt *conn1D=0,*conn1DI=0;
5342 std::set<INTERP_KERNEL::NormalizedCellType> types1D;
5343 DataArrayDouble *coordsTmp=0;
5344 MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=0;
5345 MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5346 MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5347 const int *c1DPtr=conn1D->begin();
5348 const int *c1DIPtr=conn1DI->begin();
5349 int nbOfCells=getNumberOfCells();
5350 const int *cPtr=_nodal_connec->getConstPointer();
5351 const int *icPtr=_nodal_connec_index->getConstPointer();
5353 for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++)
5355 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5356 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5357 if(!cm.isQuadratic())
5359 INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType();
5360 types.insert(typ2); newConn->pushBackSilent(typ2);
5361 newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5362 for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5363 newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5364 lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0]);
5365 newConnI->pushBackSilent(lastVal);
5366 ret->pushBackSilent(i);
5371 lastVal+=(icPtr[1]-icPtr[0]);
5372 newConnI->pushBackSilent(lastVal);
5373 newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5376 conn=newConn.retn(); connI=newConnI.retn(); coords=coordsTmpSafe.retn();
5381 * Implementes \a conversionType 0 for meshes with meshDim = 2, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5382 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5383 * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5385 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic2D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5387 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5388 MCAuto<MEDCouplingUMesh> m1D=buildDescendingConnectivity(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5389 return convertLinearCellsToQuadratic2DAnd3D0(m1D,desc,descI,conn,connI,coords,types);
5392 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic2D1(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5394 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5395 MCAuto<MEDCouplingUMesh> m1D=buildDescendingConnectivity(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5397 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5398 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5399 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5401 MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5402 const int *descPtr(desc->begin()),*descIPtr(descI->begin());
5403 DataArrayInt *conn1D=0,*conn1DI=0;
5404 std::set<INTERP_KERNEL::NormalizedCellType> types1D;
5405 DataArrayDouble *coordsTmp=0;
5406 MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=0;
5407 MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5408 MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5409 const int *c1DPtr=conn1D->begin();
5410 const int *c1DIPtr=conn1DI->begin();
5411 int nbOfCells=getNumberOfCells();
5412 const int *cPtr=_nodal_connec->getConstPointer();
5413 const int *icPtr=_nodal_connec_index->getConstPointer();
5414 int lastVal=0,offset=coordsTmpSafe->getNumberOfTuples();
5415 for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++)
5417 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5418 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5419 if(!cm.isQuadratic())
5421 INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType2();
5422 types.insert(typ2); newConn->pushBackSilent(typ2);
5423 newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5424 for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5425 newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5426 newConn->pushBackSilent(offset+ret->getNumberOfTuples());
5427 lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0])+1;
5428 newConnI->pushBackSilent(lastVal);
5429 ret->pushBackSilent(i);
5434 lastVal+=(icPtr[1]-icPtr[0]);
5435 newConnI->pushBackSilent(lastVal);
5436 newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5439 MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5440 coords=DataArrayDouble::Aggregate(coordsTmpSafe,tmp); conn=newConn.retn(); connI=newConnI.retn();
5445 * Implementes \a conversionType 0 for meshes with meshDim = 3, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5446 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5447 * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5449 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic3D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5451 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5452 MCAuto<MEDCouplingUMesh> m1D=explode3DMeshTo1D(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5453 return convertLinearCellsToQuadratic2DAnd3D0(m1D,desc,descI,conn,connI,coords,types);
5456 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic3D1(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5458 MCAuto<DataArrayInt> desc2(DataArrayInt::New()),desc2I(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5459 MCAuto<MEDCouplingUMesh> m2D=buildDescendingConnectivityGen<MinusOneSonsGeneratorBiQuadratic>(desc2,desc2I,tmp2,tmp3,MEDCouplingFastNbrer); tmp2=0; tmp3=0;
5460 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),desc1I(DataArrayInt::New()),tmp4(DataArrayInt::New()),tmp5(DataArrayInt::New());
5461 MCAuto<MEDCouplingUMesh> m1D=explode3DMeshTo1D(desc1,desc1I,tmp4,tmp5); tmp4=0; tmp5=0;
5463 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5464 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5465 MCAuto<DataArrayInt> ret=DataArrayInt::New(),ret2=DataArrayInt::New(); ret->alloc(0,1); ret2->alloc(0,1);
5467 MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5468 const int *descPtr(desc1->begin()),*descIPtr(desc1I->begin()),*desc2Ptr(desc2->begin()),*desc2IPtr(desc2I->begin());
5469 DataArrayInt *conn1D=0,*conn1DI=0,*conn2D=0,*conn2DI=0;
5470 std::set<INTERP_KERNEL::NormalizedCellType> types1D,types2D;
5471 DataArrayDouble *coordsTmp=0,*coordsTmp2=0;
5472 MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=DataArrayInt::New(); ret1D->alloc(0,1);
5473 MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5474 MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5475 MCAuto<DataArrayInt> ret2D=m2D->convertLinearCellsToQuadratic2D1(conn2D,conn2DI,coordsTmp2,types2D); ret2D=DataArrayInt::New(); ret2D->alloc(0,1);
5476 MCAuto<DataArrayDouble> coordsTmp2Safe(coordsTmp2);
5477 MCAuto<DataArrayInt> conn2DSafe(conn2D),conn2DISafe(conn2DI);
5478 const int *c1DPtr=conn1D->begin(),*c1DIPtr=conn1DI->begin(),*c2DPtr=conn2D->begin(),*c2DIPtr=conn2DI->begin();
5479 int nbOfCells=getNumberOfCells();
5480 const int *cPtr=_nodal_connec->getConstPointer();
5481 const int *icPtr=_nodal_connec_index->getConstPointer();
5482 int lastVal=0,offset=coordsTmpSafe->getNumberOfTuples();
5483 for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++,desc2IPtr++)
5485 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5486 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5487 if(!cm.isQuadratic())
5489 INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType2();
5490 if(typ2==INTERP_KERNEL::NORM_ERROR)
5492 std::ostringstream oss; oss << "MEDCouplingUMesh::convertLinearCellsToQuadratic3D1 : On cell #" << i << " the linear cell type does not support advanced quadratization !";
5493 throw INTERP_KERNEL::Exception(oss.str().c_str());
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 for(const int *d=desc2Ptr+desc2IPtr[0];d!=desc2Ptr+desc2IPtr[1];d++)
5501 int nodeId2=c2DPtr[c2DIPtr[(*d)+1]-1];
5502 int tmpPos=newConn->getNumberOfTuples();
5503 newConn->pushBackSilent(nodeId2);
5504 ret2D->pushBackSilent(nodeId2); ret1D->pushBackSilent(tmpPos);
5506 newConn->pushBackSilent(offset+ret->getNumberOfTuples());
5507 lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0])+(desc2IPtr[1]-desc2IPtr[0])+1;
5508 newConnI->pushBackSilent(lastVal);
5509 ret->pushBackSilent(i);
5514 lastVal+=(icPtr[1]-icPtr[0]);
5515 newConnI->pushBackSilent(lastVal);
5516 newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5519 MCAuto<DataArrayInt> diffRet2D=ret2D->getDifferentValues();
5520 MCAuto<DataArrayInt> o2nRet2D=diffRet2D->invertArrayN2O2O2N(coordsTmp2Safe->getNumberOfTuples());
5521 coordsTmp2Safe=coordsTmp2Safe->selectByTupleId(diffRet2D->begin(),diffRet2D->end());
5522 MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5523 std::vector<const DataArrayDouble *> v(3); v[0]=coordsTmpSafe; v[1]=coordsTmp2Safe; v[2]=tmp;
5524 int *c=newConn->getPointer();
5525 const int *cI(newConnI->begin());
5526 for(const int *elt=ret1D->begin();elt!=ret1D->end();elt++)
5527 c[*elt]=o2nRet2D->getIJ(c[*elt],0)+offset;
5528 offset=coordsTmp2Safe->getNumberOfTuples();
5529 for(const int *elt=ret->begin();elt!=ret->end();elt++)
5530 c[cI[(*elt)+1]-1]+=offset;
5531 coords=DataArrayDouble::Aggregate(v); conn=newConn.retn(); connI=newConnI.retn();
5536 * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
5537 * In addition, returns an array mapping new cells to old ones. <br>
5538 * This method typically increases the number of cells in \a this mesh
5539 * but the number of nodes remains \b unchanged.
5540 * That's why the 3D splitting policies
5541 * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
5542 * \param [in] policy - specifies a pattern used for splitting.
5543 * The semantic of \a policy is:
5544 * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
5545 * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
5546 * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8 into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
5547 * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8 into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
5550 * \return DataArrayInt * - a new instance of DataArrayInt holding, for each new cell,
5551 * an id of old cell producing it. The caller is to delete this array using
5552 * decrRef() as it is no more needed.
5554 * \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
5555 * \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
5556 * and \a this->getMeshDimension() != 3.
5557 * \throw If \a policy is not one of the four discussed above.
5558 * \throw If the nodal connectivity of cells is not defined.
5559 * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
5561 DataArrayInt *MEDCouplingUMesh::simplexize(int policy)
5566 return simplexizePol0();
5568 return simplexizePol1();
5569 case (int) INTERP_KERNEL::PLANAR_FACE_5:
5570 return simplexizePlanarFace5();
5571 case (int) INTERP_KERNEL::PLANAR_FACE_6:
5572 return simplexizePlanarFace6();
5574 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)");
5579 * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
5580 * - 1D: INTERP_KERNEL::NORM_SEG2
5581 * - 2D: INTERP_KERNEL::NORM_TRI3
5582 * - 3D: INTERP_KERNEL::NORM_TETRA4.
5584 * This method is useful for users that need to use P1 field services as
5585 * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
5586 * All these methods need mesh support containing only simplex cells.
5587 * \return bool - \c true if there are only simplex cells in \a this mesh.
5588 * \throw If the coordinates array is not set.
5589 * \throw If the nodal connectivity of cells is not defined.
5590 * \throw If \a this->getMeshDimension() < 1.
5592 bool MEDCouplingUMesh::areOnlySimplexCells() const
5594 checkFullyDefined();
5595 int mdim=getMeshDimension();
5596 if(mdim<1 || mdim>3)
5597 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
5598 int nbCells=getNumberOfCells();
5599 const int *conn=_nodal_connec->getConstPointer();
5600 const int *connI=_nodal_connec_index->getConstPointer();
5601 for(int i=0;i<nbCells;i++)
5603 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5611 * This method implements policy 0 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5613 DataArrayInt *MEDCouplingUMesh::simplexizePol0()
5615 checkConnectivityFullyDefined();
5616 if(getMeshDimension()!=2)
5617 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePol0 : this policy is only available for mesh with meshdim == 2 !");
5618 int nbOfCells=getNumberOfCells();
5619 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5620 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_QUAD4);
5621 ret->alloc(nbOfCells+nbOfCutCells,1);
5622 if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5623 int *retPt=ret->getPointer();
5624 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5625 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5626 newConnI->alloc(nbOfCells+nbOfCutCells+1,1);
5627 newConn->alloc(getNodalConnectivityArrayLen()+3*nbOfCutCells,1);
5628 int *pt=newConn->getPointer();
5629 int *ptI=newConnI->getPointer();
5631 const int *oldc=_nodal_connec->getConstPointer();
5632 const int *ci=_nodal_connec_index->getConstPointer();
5633 for(int i=0;i<nbOfCells;i++,ci++)
5635 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_QUAD4)
5637 const int tmp[8]={(int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+2],oldc[ci[0]+3],
5638 (int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+3],oldc[ci[0]+4]};
5639 pt=std::copy(tmp,tmp+8,pt);
5648 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5649 ptI[1]=ptI[0]+ci[1]-ci[0];
5654 _nodal_connec->decrRef();
5655 _nodal_connec=newConn.retn();
5656 _nodal_connec_index->decrRef();
5657 _nodal_connec_index=newConnI.retn();
5664 * This method implements policy 1 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5666 DataArrayInt *MEDCouplingUMesh::simplexizePol1()
5668 checkConnectivityFullyDefined();
5669 if(getMeshDimension()!=2)
5670 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePol0 : this policy is only available for mesh with meshdim == 2 !");
5671 int nbOfCells=getNumberOfCells();
5672 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5673 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_QUAD4);
5674 ret->alloc(nbOfCells+nbOfCutCells,1);
5675 if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5676 int *retPt=ret->getPointer();
5677 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5678 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5679 newConnI->alloc(nbOfCells+nbOfCutCells+1,1);
5680 newConn->alloc(getNodalConnectivityArrayLen()+3*nbOfCutCells,1);
5681 int *pt=newConn->getPointer();
5682 int *ptI=newConnI->getPointer();
5684 const int *oldc=_nodal_connec->getConstPointer();
5685 const int *ci=_nodal_connec_index->getConstPointer();
5686 for(int i=0;i<nbOfCells;i++,ci++)
5688 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_QUAD4)
5690 const int tmp[8]={(int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+2],oldc[ci[0]+4],
5691 (int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+2],oldc[ci[0]+3],oldc[ci[0]+4]};
5692 pt=std::copy(tmp,tmp+8,pt);
5701 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5702 ptI[1]=ptI[0]+ci[1]-ci[0];
5707 _nodal_connec->decrRef();
5708 _nodal_connec=newConn.retn();
5709 _nodal_connec_index->decrRef();
5710 _nodal_connec_index=newConnI.retn();
5717 * This method implements policy INTERP_KERNEL::PLANAR_FACE_5 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5719 DataArrayInt *MEDCouplingUMesh::simplexizePlanarFace5()
5721 checkConnectivityFullyDefined();
5722 if(getMeshDimension()!=3)
5723 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePlanarFace5 : this policy is only available for mesh with meshdim == 3 !");
5724 int nbOfCells=getNumberOfCells();
5725 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5726 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_HEXA8);
5727 ret->alloc(nbOfCells+4*nbOfCutCells,1);
5728 if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5729 int *retPt=ret->getPointer();
5730 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5731 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5732 newConnI->alloc(nbOfCells+4*nbOfCutCells+1,1);
5733 newConn->alloc(getNodalConnectivityArrayLen()+16*nbOfCutCells,1);//21
5734 int *pt=newConn->getPointer();
5735 int *ptI=newConnI->getPointer();
5737 const int *oldc=_nodal_connec->getConstPointer();
5738 const int *ci=_nodal_connec_index->getConstPointer();
5739 for(int i=0;i<nbOfCells;i++,ci++)
5741 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_HEXA8)
5743 for(int j=0;j<5;j++,pt+=5,ptI++)
5745 pt[0]=(int)INTERP_KERNEL::NORM_TETRA4;
5746 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];
5753 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5754 ptI[1]=ptI[0]+ci[1]-ci[0];
5759 _nodal_connec->decrRef();
5760 _nodal_connec=newConn.retn();
5761 _nodal_connec_index->decrRef();
5762 _nodal_connec_index=newConnI.retn();
5769 * This method implements policy INTERP_KERNEL::PLANAR_FACE_6 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5771 DataArrayInt *MEDCouplingUMesh::simplexizePlanarFace6()
5773 checkConnectivityFullyDefined();
5774 if(getMeshDimension()!=3)
5775 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePlanarFace6 : this policy is only available for mesh with meshdim == 3 !");
5776 int nbOfCells=getNumberOfCells();
5777 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5778 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_HEXA8);
5779 ret->alloc(nbOfCells+5*nbOfCutCells,1);
5780 if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5781 int *retPt=ret->getPointer();
5782 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5783 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5784 newConnI->alloc(nbOfCells+5*nbOfCutCells+1,1);
5785 newConn->alloc(getNodalConnectivityArrayLen()+21*nbOfCutCells,1);
5786 int *pt=newConn->getPointer();
5787 int *ptI=newConnI->getPointer();
5789 const int *oldc=_nodal_connec->getConstPointer();
5790 const int *ci=_nodal_connec_index->getConstPointer();
5791 for(int i=0;i<nbOfCells;i++,ci++)
5793 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_HEXA8)
5795 for(int j=0;j<6;j++,pt+=5,ptI++)
5797 pt[0]=(int)INTERP_KERNEL::NORM_TETRA4;
5798 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];
5805 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5806 ptI[1]=ptI[0]+ci[1]-ci[0];
5811 _nodal_connec->decrRef();
5812 _nodal_connec=newConn.retn();
5813 _nodal_connec_index->decrRef();
5814 _nodal_connec_index=newConnI.retn();
5821 * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
5822 * so that the number of cells remains the same. Quadratic faces are converted to
5823 * polygons. This method works only for 2D meshes in
5824 * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
5825 * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
5826 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5827 * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
5828 * a polylinized edge constituting the input polygon.
5829 * \throw If the coordinates array is not set.
5830 * \throw If the nodal connectivity of cells is not defined.
5831 * \throw If \a this->getMeshDimension() != 2.
5832 * \throw If \a this->getSpaceDimension() != 2.
5834 void MEDCouplingUMesh::tessellate2DInternal(double eps)
5836 checkFullyDefined();
5837 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
5838 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DInternal works on umeshes with meshdim equal to 2 and spaceDim equal to 2 too!");
5839 double epsa=fabs(eps);
5840 if(epsa<std::numeric_limits<double>::min())
5841 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 !");
5842 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
5843 MCAuto<MEDCouplingUMesh> mDesc(buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1));
5844 revDesc1=0; revDescIndx1=0;
5845 mDesc->tessellate2D(eps);
5846 subDivide2DMesh(mDesc->_nodal_connec->getConstPointer(),mDesc->_nodal_connec_index->getConstPointer(),desc1->getConstPointer(),descIndx1->getConstPointer());
5847 setCoords(mDesc->getCoords());
5851 * Tessellates \a this 1D mesh in 2D space by dividing not straight quadratic edges.
5852 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5853 * \param [in] eps - specifies the maximal angle (in radian) between 2 sub-edges of
5854 * a sub-divided edge.
5855 * \throw If the coordinates array is not set.
5856 * \throw If the nodal connectivity of cells is not defined.
5857 * \throw If \a this->getMeshDimension() != 1.
5858 * \throw If \a this->getSpaceDimension() != 2.
5860 void MEDCouplingUMesh::tessellate2DCurveInternal(double eps)
5862 checkFullyDefined();
5863 if(getMeshDimension()!=1 || getSpaceDimension()!=2)
5864 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DCurveInternal works on umeshes with meshdim equal to 1 and spaceDim equal to 2 too!");
5865 double epsa=fabs(eps);
5866 if(epsa<std::numeric_limits<double>::min())
5867 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 !");
5868 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=1.e-10;
5869 int nbCells=getNumberOfCells();
5870 int nbNodes=getNumberOfNodes();
5871 const int *conn=_nodal_connec->getConstPointer();
5872 const int *connI=_nodal_connec_index->getConstPointer();
5873 const double *coords=_coords->getConstPointer();
5874 std::vector<double> addCoo;
5875 std::vector<int> newConn;//no direct DataArrayInt because interface with Geometric2D
5876 MCAuto<DataArrayInt> newConnI(DataArrayInt::New());
5877 newConnI->alloc(nbCells+1,1);
5878 int *newConnIPtr=newConnI->getPointer();
5881 INTERP_KERNEL::Node *tmp2[3];
5882 std::set<INTERP_KERNEL::NormalizedCellType> types;
5883 for(int i=0;i<nbCells;i++,newConnIPtr++)
5885 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5886 if(cm.isQuadratic())
5887 {//assert(connI[i+1]-connI[i]-1==3)
5888 tmp1[0]=conn[connI[i]+1+0]; tmp1[1]=conn[connI[i]+1+1]; tmp1[2]=conn[connI[i]+1+2];
5889 tmp2[0]=new INTERP_KERNEL::Node(coords[2*tmp1[0]],coords[2*tmp1[0]+1]);
5890 tmp2[1]=new INTERP_KERNEL::Node(coords[2*tmp1[1]],coords[2*tmp1[1]+1]);
5891 tmp2[2]=new INTERP_KERNEL::Node(coords[2*tmp1[2]],coords[2*tmp1[2]+1]);
5892 INTERP_KERNEL::EdgeArcCircle *eac=INTERP_KERNEL::EdgeArcCircle::BuildFromNodes(tmp2[0],tmp2[2],tmp2[1]);
5895 eac->tesselate(tmp1,nbNodes,epsa,newConn,addCoo);
5896 types.insert((INTERP_KERNEL::NormalizedCellType)newConn[newConnIPtr[0]]);
5898 newConnIPtr[1]=(int)newConn.size();
5902 types.insert(INTERP_KERNEL::NORM_SEG2);
5903 newConn.push_back(INTERP_KERNEL::NORM_SEG2);
5904 newConn.insert(newConn.end(),conn+connI[i]+1,conn+connI[i]+3);
5905 newConnIPtr[1]=newConnIPtr[0]+3;
5910 types.insert((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5911 newConn.insert(newConn.end(),conn+connI[i],conn+connI[i+1]);
5912 newConnIPtr[1]=newConnIPtr[0]+3;
5915 if(addCoo.empty() && ((int)newConn.size())==_nodal_connec->getNumberOfTuples())//nothing happens during tessellation : no update needed
5918 DataArrayInt::SetArrayIn(newConnI,_nodal_connec_index);
5919 MCAuto<DataArrayInt> newConnArr=DataArrayInt::New();
5920 newConnArr->alloc((int)newConn.size(),1);
5921 std::copy(newConn.begin(),newConn.end(),newConnArr->getPointer());
5922 DataArrayInt::SetArrayIn(newConnArr,_nodal_connec);
5923 MCAuto<DataArrayDouble> newCoords=DataArrayDouble::New();
5924 newCoords->alloc(nbNodes+((int)addCoo.size())/2,2);
5925 double *work=std::copy(_coords->begin(),_coords->end(),newCoords->getPointer());
5926 std::copy(addCoo.begin(),addCoo.end(),work);
5927 DataArrayDouble::SetArrayIn(newCoords,_coords);
5932 * 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.
5933 * This method completly ignore coordinates.
5934 * \param nodeSubdived is the nodal connectivity of subdivision of edges
5935 * \param nodeIndxSubdived is the nodal connectivity index of subdivision of edges
5936 * \param desc is descending connectivity in format specified in MEDCouplingUMesh::buildDescendingConnectivity2
5937 * \param descIndex is descending connectivity index in format specified in MEDCouplingUMesh::buildDescendingConnectivity2
5939 void MEDCouplingUMesh::subDivide2DMesh(const int *nodeSubdived, const int *nodeIndxSubdived, const int *desc, const int *descIndex)
5941 checkFullyDefined();
5942 if(getMeshDimension()!=2)
5943 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::subDivide2DMesh : works only on umesh with meshdim==2 !");
5944 int nbOfCells=getNumberOfCells();
5945 int *connI=_nodal_connec_index->getPointer();
5947 for(int i=0;i<nbOfCells;i++,connI++)
5949 int offset=descIndex[i];
5950 int nbOfEdges=descIndex[i+1]-offset;
5952 bool ddirect=desc[offset+nbOfEdges-1]>0;
5953 int eedgeId=std::abs(desc[offset+nbOfEdges-1])-1;
5954 int ref=ddirect?nodeSubdived[nodeIndxSubdived[eedgeId+1]-1]:nodeSubdived[nodeIndxSubdived[eedgeId]+1];
5955 for(int j=0;j<nbOfEdges;j++)
5957 bool direct=desc[offset+j]>0;
5958 int edgeId=std::abs(desc[offset+j])-1;
5959 if(!INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodeSubdived[nodeIndxSubdived[edgeId]]).isQuadratic())
5961 int id1=nodeSubdived[nodeIndxSubdived[edgeId]+1];
5962 int id2=nodeSubdived[nodeIndxSubdived[edgeId+1]-1];
5963 int ref2=direct?id1:id2;
5966 int nbOfSubNodes=nodeIndxSubdived[edgeId+1]-nodeIndxSubdived[edgeId]-1;
5967 newConnLgth+=nbOfSubNodes-1;
5972 std::ostringstream oss; oss << "MEDCouplingUMesh::subDivide2DMesh : On polygon #" << i << " edgeid #" << j << " subedges mismatch : end subedge k!=start subedge k+1 !";
5973 throw INTERP_KERNEL::Exception(oss.str().c_str());
5978 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::subDivide2DMesh : this method only subdivides into linear edges !");
5981 newConnLgth++;//+1 is for cell type
5982 connI[1]=newConnLgth;
5985 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5986 newConn->alloc(newConnLgth,1);
5987 int *work=newConn->getPointer();
5988 for(int i=0;i<nbOfCells;i++)
5990 *work++=INTERP_KERNEL::NORM_POLYGON;
5991 int offset=descIndex[i];
5992 int nbOfEdges=descIndex[i+1]-offset;
5993 for(int j=0;j<nbOfEdges;j++)
5995 bool direct=desc[offset+j]>0;
5996 int edgeId=std::abs(desc[offset+j])-1;
5998 work=std::copy(nodeSubdived+nodeIndxSubdived[edgeId]+1,nodeSubdived+nodeIndxSubdived[edgeId+1]-1,work);
6001 int nbOfSubNodes=nodeIndxSubdived[edgeId+1]-nodeIndxSubdived[edgeId]-1;
6002 std::reverse_iterator<const int *> it(nodeSubdived+nodeIndxSubdived[edgeId+1]);
6003 work=std::copy(it,it+nbOfSubNodes-1,work);
6007 DataArrayInt::SetArrayIn(newConn,_nodal_connec);
6010 _types.insert(INTERP_KERNEL::NORM_POLYGON);
6014 * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
6015 * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
6016 * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell. This method
6017 * does \b not perform geometrical checks and checks only nodal connectivity of cells,
6018 * so it can be useful to call mergeNodes() before calling this method.
6019 * \throw If \a this->getMeshDimension() <= 1.
6020 * \throw If the coordinates array is not set.
6021 * \throw If the nodal connectivity of cells is not defined.
6023 void MEDCouplingUMesh::convertDegeneratedCells()
6025 checkFullyDefined();
6026 if(getMeshDimension()<=1)
6027 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
6028 int nbOfCells=getNumberOfCells();
6031 int initMeshLgth=getNodalConnectivityArrayLen();
6032 int *conn=_nodal_connec->getPointer();
6033 int *index=_nodal_connec_index->getPointer();
6037 for(int i=0;i<nbOfCells;i++)
6039 lgthOfCurCell=index[i+1]-posOfCurCell;
6040 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
6042 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
6043 conn+newPos+1,newLgth);
6044 conn[newPos]=newType;
6046 posOfCurCell=index[i+1];
6049 if(newPos!=initMeshLgth)
6050 _nodal_connec->reAlloc(newPos);
6055 * Finds incorrectly oriented cells of this 2D mesh in 3D space.
6056 * A cell is considered to be oriented correctly if an angle between its
6057 * normal vector and a given vector is less than \c PI / \c 2.
6058 * \param [in] vec - 3 components of the vector specifying the correct orientation of
6060 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
6062 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
6063 * is not cleared before filling in.
6064 * \throw If \a this->getMeshDimension() != 2.
6065 * \throw If \a this->getSpaceDimension() != 3.
6067 * \if ENABLE_EXAMPLES
6068 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
6069 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
6072 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<int>& cells) const
6074 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6075 throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
6076 int nbOfCells=getNumberOfCells();
6077 const int *conn=_nodal_connec->getConstPointer();
6078 const int *connI=_nodal_connec_index->getConstPointer();
6079 const double *coordsPtr=_coords->getConstPointer();
6080 for(int i=0;i<nbOfCells;i++)
6082 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6083 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
6085 bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
6086 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6093 * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
6094 * considered to be oriented correctly if an angle between its normal vector and a
6095 * given vector is less than \c PI / \c 2.
6096 * \param [in] vec - 3 components of the vector specifying the correct orientation of
6098 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
6100 * \throw If \a this->getMeshDimension() != 2.
6101 * \throw If \a this->getSpaceDimension() != 3.
6103 * \if ENABLE_EXAMPLES
6104 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
6105 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
6108 * \sa changeOrientationOfCells
6110 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
6112 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6113 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
6114 int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
6115 const int *connI(_nodal_connec_index->getConstPointer());
6116 const double *coordsPtr(_coords->getConstPointer());
6117 bool isModified(false);
6118 for(int i=0;i<nbOfCells;i++)
6120 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6121 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
6123 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6124 bool isQuadratic(cm.isQuadratic());
6125 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6128 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6133 _nodal_connec->declareAsNew();
6138 * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
6140 * \sa orientCorrectly2DCells
6142 void MEDCouplingUMesh::changeOrientationOfCells()
6144 int mdim(getMeshDimension());
6145 if(mdim!=2 && mdim!=1)
6146 throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
6147 int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
6148 const int *connI(_nodal_connec_index->getConstPointer());
6151 for(int i=0;i<nbOfCells;i++)
6153 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6154 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6155 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6160 for(int i=0;i<nbOfCells;i++)
6162 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6163 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6164 cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6170 * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
6171 * oriented facets. The normal vector of the facet should point out of the cell.
6172 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
6173 * is not cleared before filling in.
6174 * \throw If \a this->getMeshDimension() != 3.
6175 * \throw If \a this->getSpaceDimension() != 3.
6176 * \throw If the coordinates array is not set.
6177 * \throw If the nodal connectivity of cells is not defined.
6179 * \if ENABLE_EXAMPLES
6180 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
6181 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
6184 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<int>& cells) const
6186 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6187 throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
6188 int nbOfCells=getNumberOfCells();
6189 const int *conn=_nodal_connec->getConstPointer();
6190 const int *connI=_nodal_connec_index->getConstPointer();
6191 const double *coordsPtr=_coords->getConstPointer();
6192 for(int i=0;i<nbOfCells;i++)
6194 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6195 if(type==INTERP_KERNEL::NORM_POLYHED)
6197 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6204 * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
6206 * \throw If \a this->getMeshDimension() != 3.
6207 * \throw If \a this->getSpaceDimension() != 3.
6208 * \throw If the coordinates array is not set.
6209 * \throw If the nodal connectivity of cells is not defined.
6210 * \throw If the reparation fails.
6212 * \if ENABLE_EXAMPLES
6213 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
6214 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
6216 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
6218 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
6220 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6221 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
6222 int nbOfCells=getNumberOfCells();
6223 int *conn=_nodal_connec->getPointer();
6224 const int *connI=_nodal_connec_index->getConstPointer();
6225 const double *coordsPtr=_coords->getConstPointer();
6226 for(int i=0;i<nbOfCells;i++)
6228 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6229 if(type==INTERP_KERNEL::NORM_POLYHED)
6233 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6234 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
6236 catch(INTERP_KERNEL::Exception& e)
6238 std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
6239 throw INTERP_KERNEL::Exception(oss.str().c_str());
6247 * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
6248 * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
6249 * according to which the first facet of the cell should be oriented to have the normal vector
6250 * pointing out of cell.
6251 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of fixed
6252 * cells. The caller is to delete this array using decrRef() as it is no more
6254 * \throw If \a this->getMeshDimension() != 3.
6255 * \throw If \a this->getSpaceDimension() != 3.
6256 * \throw If the coordinates array is not set.
6257 * \throw If the nodal connectivity of cells is not defined.
6259 * \if ENABLE_EXAMPLES
6260 * \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
6261 * \ref py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
6263 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
6265 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
6267 const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
6268 if(getMeshDimension()!=3)
6269 throw INTERP_KERNEL::Exception(msg);
6270 int spaceDim=getSpaceDimension();
6272 throw INTERP_KERNEL::Exception(msg);
6274 int nbOfCells=getNumberOfCells();
6275 int *conn=_nodal_connec->getPointer();
6276 const int *connI=_nodal_connec_index->getConstPointer();
6277 const double *coo=getCoords()->getConstPointer();
6278 MCAuto<DataArrayInt> cells(DataArrayInt::New()); cells->alloc(0,1);
6279 for(int i=0;i<nbOfCells;i++)
6281 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6282 if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
6284 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
6286 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
6287 cells->pushBackSilent(i);
6291 return cells.retn();
6295 * This method is a faster method to correct orientation of all 3D cells in \a this.
6296 * 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.
6297 * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
6299 * \return a newly allocated int array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
6300 * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
6302 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
6304 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6305 throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
6306 int nbOfCells=getNumberOfCells();
6307 int *conn=_nodal_connec->getPointer();
6308 const int *connI=_nodal_connec_index->getConstPointer();
6309 const double *coordsPtr=_coords->getConstPointer();
6310 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
6311 for(int i=0;i<nbOfCells;i++)
6313 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6316 case INTERP_KERNEL::NORM_TETRA4:
6318 if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6320 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
6321 ret->pushBackSilent(i);
6325 case INTERP_KERNEL::NORM_PYRA5:
6327 if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6329 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
6330 ret->pushBackSilent(i);
6334 case INTERP_KERNEL::NORM_PENTA6:
6335 case INTERP_KERNEL::NORM_HEXA8:
6336 case INTERP_KERNEL::NORM_HEXGP12:
6338 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6340 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
6341 ret->pushBackSilent(i);
6345 case INTERP_KERNEL::NORM_POLYHED:
6347 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6349 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
6350 ret->pushBackSilent(i);
6355 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 !");
6363 * This method has a sense for meshes with spaceDim==3 and meshDim==2.
6364 * If it is not the case an exception will be thrown.
6365 * This method is fast because the first cell of \a this is used to compute the plane.
6366 * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
6367 * \param pos output of size at least 3 used to store a point owned of searched plane.
6369 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
6371 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6372 throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
6373 const int *conn=_nodal_connec->getConstPointer();
6374 const int *connI=_nodal_connec_index->getConstPointer();
6375 const double *coordsPtr=_coords->getConstPointer();
6376 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
6377 std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
6381 * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
6382 * cells. Currently cells of the following types are treated:
6383 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
6384 * For a cell of other type an exception is thrown.
6385 * Space dimension of a 2D mesh can be either 2 or 3.
6386 * The Edge Ratio of a cell \f$t\f$ is:
6387 * \f$\frac{|t|_\infty}{|t|_0}\f$,
6388 * where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
6389 * the smallest edge lengths of \f$t\f$.
6390 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6391 * cells and one time, lying on \a this mesh. The caller is to delete this
6392 * field using decrRef() as it is no more needed.
6393 * \throw If the coordinates array is not set.
6394 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6395 * \throw If the connectivity data array has more than one component.
6396 * \throw If the connectivity data array has a named component.
6397 * \throw If the connectivity index data array has more than one component.
6398 * \throw If the connectivity index data array has a named component.
6399 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
6400 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
6401 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
6403 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
6405 checkConsistencyLight();
6406 int spaceDim=getSpaceDimension();
6407 int meshDim=getMeshDimension();
6408 if(spaceDim!=2 && spaceDim!=3)
6409 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
6410 if(meshDim!=2 && meshDim!=3)
6411 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
6412 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6414 int nbOfCells=getNumberOfCells();
6415 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6416 arr->alloc(nbOfCells,1);
6417 double *pt=arr->getPointer();
6418 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6419 const int *conn=_nodal_connec->getConstPointer();
6420 const int *connI=_nodal_connec_index->getConstPointer();
6421 const double *coo=_coords->getConstPointer();
6423 for(int i=0;i<nbOfCells;i++,pt++)
6425 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6428 case INTERP_KERNEL::NORM_TRI3:
6430 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
6431 *pt=INTERP_KERNEL::triEdgeRatio(tmp);
6434 case INTERP_KERNEL::NORM_QUAD4:
6436 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6437 *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
6440 case INTERP_KERNEL::NORM_TETRA4:
6442 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6443 *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
6447 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
6449 conn+=connI[i+1]-connI[i];
6451 ret->setName("EdgeRatio");
6452 ret->synchronizeTimeWithSupport();
6457 * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
6458 * cells. Currently cells of the following types are treated:
6459 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
6460 * For a cell of other type an exception is thrown.
6461 * Space dimension of a 2D mesh can be either 2 or 3.
6462 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6463 * cells and one time, lying on \a this mesh. The caller is to delete this
6464 * field using decrRef() as it is no more needed.
6465 * \throw If the coordinates array is not set.
6466 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6467 * \throw If the connectivity data array has more than one component.
6468 * \throw If the connectivity data array has a named component.
6469 * \throw If the connectivity index data array has more than one component.
6470 * \throw If the connectivity index data array has a named component.
6471 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
6472 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
6473 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
6475 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
6477 checkConsistencyLight();
6478 int spaceDim=getSpaceDimension();
6479 int meshDim=getMeshDimension();
6480 if(spaceDim!=2 && spaceDim!=3)
6481 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
6482 if(meshDim!=2 && meshDim!=3)
6483 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
6484 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6486 int nbOfCells=getNumberOfCells();
6487 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6488 arr->alloc(nbOfCells,1);
6489 double *pt=arr->getPointer();
6490 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6491 const int *conn=_nodal_connec->getConstPointer();
6492 const int *connI=_nodal_connec_index->getConstPointer();
6493 const double *coo=_coords->getConstPointer();
6495 for(int i=0;i<nbOfCells;i++,pt++)
6497 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6500 case INTERP_KERNEL::NORM_TRI3:
6502 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
6503 *pt=INTERP_KERNEL::triAspectRatio(tmp);
6506 case INTERP_KERNEL::NORM_QUAD4:
6508 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6509 *pt=INTERP_KERNEL::quadAspectRatio(tmp);
6512 case INTERP_KERNEL::NORM_TETRA4:
6514 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6515 *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
6519 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
6521 conn+=connI[i+1]-connI[i];
6523 ret->setName("AspectRatio");
6524 ret->synchronizeTimeWithSupport();
6529 * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
6530 * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
6531 * in 3D space. Currently only cells of the following types are
6532 * treated: INTERP_KERNEL::NORM_QUAD4.
6533 * For a cell of other type an exception is thrown.
6534 * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
6536 * \f$t=\vec{da}\times\vec{ab}\f$,
6537 * \f$u=\vec{ab}\times\vec{bc}\f$
6538 * \f$v=\vec{bc}\times\vec{cd}\f$
6539 * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
6541 * W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
6543 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6544 * cells and one time, lying on \a this mesh. The caller is to delete this
6545 * field using decrRef() as it is no more needed.
6546 * \throw If the coordinates array is not set.
6547 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6548 * \throw If the connectivity data array has more than one component.
6549 * \throw If the connectivity data array has a named component.
6550 * \throw If the connectivity index data array has more than one component.
6551 * \throw If the connectivity index data array has a named component.
6552 * \throw If \a this->getMeshDimension() != 2.
6553 * \throw If \a this->getSpaceDimension() != 3.
6554 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
6556 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
6558 checkConsistencyLight();
6559 int spaceDim=getSpaceDimension();
6560 int meshDim=getMeshDimension();
6562 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
6564 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
6565 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6567 int nbOfCells=getNumberOfCells();
6568 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6569 arr->alloc(nbOfCells,1);
6570 double *pt=arr->getPointer();
6571 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6572 const int *conn=_nodal_connec->getConstPointer();
6573 const int *connI=_nodal_connec_index->getConstPointer();
6574 const double *coo=_coords->getConstPointer();
6576 for(int i=0;i<nbOfCells;i++,pt++)
6578 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6581 case INTERP_KERNEL::NORM_QUAD4:
6583 FillInCompact3DMode(3,4,conn+1,coo,tmp);
6584 *pt=INTERP_KERNEL::quadWarp(tmp);
6588 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
6590 conn+=connI[i+1]-connI[i];
6592 ret->setName("Warp");
6593 ret->synchronizeTimeWithSupport();
6599 * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
6600 * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
6601 * treated: INTERP_KERNEL::NORM_QUAD4.
6602 * The skew is computed as follow for a quad with points (a,b,c,d): let
6603 * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
6604 * then the skew is computed as:
6606 * s=\frac{u}{|u|}\cdot\frac{v}{|v|}
6609 * For a cell of other type an exception is thrown.
6610 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6611 * cells and one time, lying on \a this mesh. The caller is to delete this
6612 * field using decrRef() as it is no more needed.
6613 * \throw If the coordinates array is not set.
6614 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6615 * \throw If the connectivity data array has more than one component.
6616 * \throw If the connectivity data array has a named component.
6617 * \throw If the connectivity index data array has more than one component.
6618 * \throw If the connectivity index data array has a named component.
6619 * \throw If \a this->getMeshDimension() != 2.
6620 * \throw If \a this->getSpaceDimension() != 3.
6621 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
6623 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
6625 checkConsistencyLight();
6626 int spaceDim=getSpaceDimension();
6627 int meshDim=getMeshDimension();
6629 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
6631 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
6632 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6634 int nbOfCells=getNumberOfCells();
6635 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6636 arr->alloc(nbOfCells,1);
6637 double *pt=arr->getPointer();
6638 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6639 const int *conn=_nodal_connec->getConstPointer();
6640 const int *connI=_nodal_connec_index->getConstPointer();
6641 const double *coo=_coords->getConstPointer();
6643 for(int i=0;i<nbOfCells;i++,pt++)
6645 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6648 case INTERP_KERNEL::NORM_QUAD4:
6650 FillInCompact3DMode(3,4,conn+1,coo,tmp);
6651 *pt=INTERP_KERNEL::quadSkew(tmp);
6655 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
6657 conn+=connI[i+1]-connI[i];
6659 ret->setName("Skew");
6660 ret->synchronizeTimeWithSupport();
6665 * 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.
6667 * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
6669 * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
6671 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
6673 checkConsistencyLight();
6674 MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
6676 std::set<INTERP_KERNEL::NormalizedCellType> types;
6677 ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
6678 int spaceDim(getSpaceDimension()),nbCells(getNumberOfCells());
6679 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6680 arr->alloc(nbCells,1);
6681 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
6683 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
6684 MCAuto<DataArrayInt> cellIds(giveCellsWithType(*it));
6685 dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
6688 ret->setName("Diameter");
6693 * This method aggregate the bbox of each cell and put it into bbox parameter.
6695 * \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)
6696 * For all other cases this input parameter is ignored.
6697 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6699 * \throw If \a this is not fully set (coordinates and connectivity).
6700 * \throw If a cell in \a this has no valid nodeId.
6701 * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
6703 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
6705 int mDim(getMeshDimension()),sDim(getSpaceDimension());
6706 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.
6707 return getBoundingBoxForBBTreeFast();
6708 if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
6710 bool presenceOfQuadratic(false);
6711 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
6713 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
6714 if(cm.isQuadratic())
6715 presenceOfQuadratic=true;
6717 if(!presenceOfQuadratic)
6718 return getBoundingBoxForBBTreeFast();
6719 if(mDim==2 && sDim==2)
6720 return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
6722 return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
6724 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) !");
6728 * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
6729 * So meshes having quadratic cells the computed bounding boxes can be invalid !
6731 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6733 * \throw If \a this is not fully set (coordinates and connectivity).
6734 * \throw If a cell in \a this has no valid nodeId.
6736 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
6738 checkFullyDefined();
6739 int spaceDim(getSpaceDimension()),nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
6740 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6741 double *bbox(ret->getPointer());
6742 for(int i=0;i<nbOfCells*spaceDim;i++)
6744 bbox[2*i]=std::numeric_limits<double>::max();
6745 bbox[2*i+1]=-std::numeric_limits<double>::max();
6747 const double *coordsPtr(_coords->getConstPointer());
6748 const int *conn(_nodal_connec->getConstPointer()),*connI(_nodal_connec_index->getConstPointer());
6749 for(int i=0;i<nbOfCells;i++)
6751 int offset=connI[i]+1;
6752 int nbOfNodesForCell(connI[i+1]-offset),kk(0);
6753 for(int j=0;j<nbOfNodesForCell;j++)
6755 int nodeId=conn[offset+j];
6756 if(nodeId>=0 && nodeId<nbOfNodes)
6758 for(int k=0;k<spaceDim;k++)
6760 bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
6761 bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
6768 std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
6769 throw INTERP_KERNEL::Exception(oss.str().c_str());
6776 * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
6777 * useful for 2D meshes having quadratic cells
6778 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
6779 * the two extremities of the arc of circle).
6781 * \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)
6782 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6783 * \throw If \a this is not fully defined.
6784 * \throw If \a this is not a mesh with meshDimension equal to 2.
6785 * \throw If \a this is not a mesh with spaceDimension equal to 2.
6786 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
6788 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
6790 checkFullyDefined();
6791 int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
6792 if(spaceDim!=2 || mDim!=2)
6793 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!");
6794 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6795 double *bbox(ret->getPointer());
6796 const double *coords(_coords->getConstPointer());
6797 const int *conn(_nodal_connec->getConstPointer()),*connI(_nodal_connec_index->getConstPointer());
6798 for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
6800 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
6801 int sz(connI[1]-connI[0]-1);
6802 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=arcDetEps;
6803 std::vector<INTERP_KERNEL::Node *> nodes(sz);
6804 INTERP_KERNEL::QuadraticPolygon *pol(0);
6805 for(int j=0;j<sz;j++)
6807 int nodeId(conn[*connI+1+j]);
6808 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
6810 if(!cm.isQuadratic())
6811 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
6813 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
6814 INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
6815 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
6821 * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
6822 * useful for 2D meshes having quadratic cells
6823 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
6824 * the two extremities of the arc of circle).
6826 * \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)
6827 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6828 * \throw If \a this is not fully defined.
6829 * \throw If \a this is not a mesh with meshDimension equal to 1.
6830 * \throw If \a this is not a mesh with spaceDimension equal to 2.
6831 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
6833 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
6835 checkFullyDefined();
6836 int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
6837 if(spaceDim!=2 || mDim!=1)
6838 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!");
6839 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6840 double *bbox(ret->getPointer());
6841 const double *coords(_coords->getConstPointer());
6842 const int *conn(_nodal_connec->getConstPointer()),*connI(_nodal_connec_index->getConstPointer());
6843 for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
6845 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
6846 int sz(connI[1]-connI[0]-1);
6847 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=arcDetEps;
6848 std::vector<INTERP_KERNEL::Node *> nodes(sz);
6849 INTERP_KERNEL::Edge *edge(0);
6850 for(int j=0;j<sz;j++)
6852 int nodeId(conn[*connI+1+j]);
6853 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
6855 if(!cm.isQuadratic())
6856 edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
6858 edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
6859 const INTERP_KERNEL::Bounds& b(edge->getBounds());
6860 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
6867 namespace MEDCouplingImpl
6872 ConnReader(const int *c, int val):_conn(c),_val(val) { }
6873 bool operator() (const int& pos) { return _conn[pos]!=_val; }
6882 ConnReader2(const int *c, int val):_conn(c),_val(val) { }
6883 bool operator() (const int& pos) { return _conn[pos]==_val; }
6893 * This method expects that \a this is sorted by types. If not an exception will be thrown.
6894 * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
6895 * \a this is composed in cell types.
6896 * The returned array is of size 3*n where n is the number of different types present in \a this.
6897 * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
6898 * This parameter is kept only for compatibility with other methode listed above.
6900 std::vector<int> MEDCouplingUMesh::getDistributionOfTypes() const
6902 checkConnectivityFullyDefined();
6903 const int *conn=_nodal_connec->getConstPointer();
6904 const int *connI=_nodal_connec_index->getConstPointer();
6905 const int *work=connI;
6906 int nbOfCells=getNumberOfCells();
6907 std::size_t n=getAllGeoTypes().size();
6908 std::vector<int> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
6909 std::set<INTERP_KERNEL::NormalizedCellType> types;
6910 for(std::size_t i=0;work!=connI+nbOfCells;i++)
6912 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
6913 if(types.find(typ)!=types.end())
6915 std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
6916 oss << " is not contiguous !";
6917 throw INTERP_KERNEL::Exception(oss.str().c_str());
6921 const int *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
6922 ret[3*i+1]=(int)std::distance(work,work2);
6929 * This method is used to check that this has contiguous cell type in same order than described in \a code.
6930 * only for types cell, type node is not managed.
6931 * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
6932 * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
6933 * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
6934 * If 2 or more same geometric type is in \a code and exception is thrown too.
6936 * This method firstly checks
6937 * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
6938 * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
6939 * an exception is thrown too.
6941 * If all geometric types in \a code are exactly those in \a this null pointer is returned.
6942 * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
6943 * and a DataArrayInt instance is returned that the user has the responsability to deallocate.
6945 DataArrayInt *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<int>& code, const std::vector<const DataArrayInt *>& idsPerType) const
6948 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
6949 std::size_t sz=code.size();
6952 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
6953 std::vector<INTERP_KERNEL::NormalizedCellType> types;
6955 bool isNoPflUsed=true;
6956 for(std::size_t i=0;i<n;i++)
6957 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
6959 types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
6961 if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
6962 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
6963 isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
6966 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
6969 if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
6970 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
6971 if(types.size()==_types.size())
6974 MCAuto<DataArrayInt> ret=DataArrayInt::New();
6976 int *retPtr=ret->getPointer();
6977 const int *connI=_nodal_connec_index->getConstPointer();
6978 const int *conn=_nodal_connec->getConstPointer();
6979 int nbOfCells=getNumberOfCells();
6982 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
6984 i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,(int)(*it)));
6985 int offset=(int)std::distance(connI,i);
6986 const int *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)(*it)));
6987 int nbOfCellsOfCurType=(int)std::distance(i,j);
6988 if(code[3*kk+2]==-1)
6989 for(int k=0;k<nbOfCellsOfCurType;k++)
6993 int idInIdsPerType=code[3*kk+2];
6994 if(idInIdsPerType>=0 && idInIdsPerType<(int)idsPerType.size())
6996 const DataArrayInt *zePfl=idsPerType[idInIdsPerType];
6999 zePfl->checkAllocated();
7000 if(zePfl->getNumberOfComponents()==1)
7002 for(const int *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
7004 if(*k>=0 && *k<nbOfCellsOfCurType)
7005 *retPtr=(*k)+offset;
7008 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
7009 oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
7010 throw INTERP_KERNEL::Exception(oss.str().c_str());
7015 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
7018 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
7022 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
7023 oss << " should be in [0," << idsPerType.size() << ") !";
7024 throw INTERP_KERNEL::Exception(oss.str().c_str());
7033 * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
7034 * 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.
7035 * 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.
7036 * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
7038 * \param [in] profile
7039 * \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.
7040 * \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,
7041 * \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
7042 * \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.
7043 * This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
7044 * \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
7046 void MEDCouplingUMesh::splitProfilePerType(const DataArrayInt *profile, std::vector<int>& code, std::vector<DataArrayInt *>& idsInPflPerType, std::vector<DataArrayInt *>& idsPerType) const
7049 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
7050 if(profile->getNumberOfComponents()!=1)
7051 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
7052 checkConnectivityFullyDefined();
7053 const int *conn=_nodal_connec->getConstPointer();
7054 const int *connI=_nodal_connec_index->getConstPointer();
7055 int nbOfCells=getNumberOfCells();
7056 std::vector<INTERP_KERNEL::NormalizedCellType> types;
7057 std::vector<int> typeRangeVals(1);
7058 for(const int *i=connI;i!=connI+nbOfCells;)
7060 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7061 if(std::find(types.begin(),types.end(),curType)!=types.end())
7063 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
7065 types.push_back(curType);
7066 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7067 typeRangeVals.push_back((int)std::distance(connI,i));
7070 DataArrayInt *castArr=0,*rankInsideCast=0,*castsPresent=0;
7071 profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
7072 MCAuto<DataArrayInt> tmp0=castArr;
7073 MCAuto<DataArrayInt> tmp1=rankInsideCast;
7074 MCAuto<DataArrayInt> tmp2=castsPresent;
7076 int nbOfCastsFinal=castsPresent->getNumberOfTuples();
7077 code.resize(3*nbOfCastsFinal);
7078 std::vector< MCAuto<DataArrayInt> > idsInPflPerType2;
7079 std::vector< MCAuto<DataArrayInt> > idsPerType2;
7080 for(int i=0;i<nbOfCastsFinal;i++)
7082 int castId=castsPresent->getIJ(i,0);
7083 MCAuto<DataArrayInt> tmp3=castArr->findIdsEqual(castId);
7084 idsInPflPerType2.push_back(tmp3);
7085 code[3*i]=(int)types[castId];
7086 code[3*i+1]=tmp3->getNumberOfTuples();
7087 MCAuto<DataArrayInt> tmp4=rankInsideCast->selectByTupleId(tmp3->getConstPointer(),tmp3->getConstPointer()+tmp3->getNumberOfTuples());
7088 if(!tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
7090 tmp4->copyStringInfoFrom(*profile);
7091 idsPerType2.push_back(tmp4);
7092 code[3*i+2]=(int)idsPerType2.size()-1;
7099 std::size_t sz2=idsInPflPerType2.size();
7100 idsInPflPerType.resize(sz2);
7101 for(std::size_t i=0;i<sz2;i++)
7103 DataArrayInt *locDa=idsInPflPerType2[i];
7105 idsInPflPerType[i]=locDa;
7107 std::size_t sz=idsPerType2.size();
7108 idsPerType.resize(sz);
7109 for(std::size_t i=0;i<sz;i++)
7111 DataArrayInt *locDa=idsPerType2[i];
7113 idsPerType[i]=locDa;
7118 * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
7119 * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
7120 * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
7121 * 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.
7123 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *&revDesc, DataArrayInt *&revDescIndx, DataArrayInt *& nM1LevMeshIds, DataArrayInt *&meshnM1Old2New) const
7125 checkFullyDefined();
7126 nM1LevMesh->checkFullyDefined();
7127 if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
7128 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
7129 if(_coords!=nM1LevMesh->getCoords())
7130 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
7131 MCAuto<DataArrayInt> tmp0=DataArrayInt::New();
7132 MCAuto<DataArrayInt> tmp1=DataArrayInt::New();
7133 MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
7134 MCAuto<DataArrayInt> ret0=ret1->sortCellsInMEDFileFrmt();
7135 desc->transformWithIndArr(ret0->getConstPointer(),ret0->getConstPointer()+ret0->getNbOfElems());
7136 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
7137 tmp->setConnectivity(tmp0,tmp1);
7138 tmp->renumberCells(ret0->getConstPointer(),false);
7139 revDesc=tmp->getNodalConnectivity();
7140 revDescIndx=tmp->getNodalConnectivityIndex();
7141 DataArrayInt *ret=0;
7142 if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
7145 ret->getMaxValue(tmp2);
7147 std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
7148 throw INTERP_KERNEL::Exception(oss.str().c_str());
7153 revDescIndx->incrRef();
7156 meshnM1Old2New=ret0;
7161 * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
7162 * necessary for writing the mesh to MED file. Additionally returns a permutation array
7163 * in "Old to New" mode.
7164 * \return DataArrayInt * - a new instance of DataArrayInt. The caller is to delete
7165 * this array using decrRef() as it is no more needed.
7166 * \throw If the nodal connectivity of cells is not defined.
7168 DataArrayInt *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
7170 checkConnectivityFullyDefined();
7171 MCAuto<DataArrayInt> ret=getRenumArrForMEDFileFrmt();
7172 renumberCells(ret->getConstPointer(),false);
7177 * This methods checks that cells are sorted by their types.
7178 * This method makes asumption (no check) that connectivity is correctly set before calling.
7180 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
7182 checkFullyDefined();
7183 const int *conn=_nodal_connec->getConstPointer();
7184 const int *connI=_nodal_connec_index->getConstPointer();
7185 int nbOfCells=getNumberOfCells();
7186 std::set<INTERP_KERNEL::NormalizedCellType> types;
7187 for(const int *i=connI;i!=connI+nbOfCells;)
7189 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7190 if(types.find(curType)!=types.end())
7192 types.insert(curType);
7193 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7199 * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
7200 * The geometric type order is specified by MED file.
7202 * \sa MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
7204 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
7206 return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
7210 * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
7211 * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
7212 * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
7213 * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
7215 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
7217 checkFullyDefined();
7218 const int *conn=_nodal_connec->getConstPointer();
7219 const int *connI=_nodal_connec_index->getConstPointer();
7220 int nbOfCells=getNumberOfCells();
7224 std::set<INTERP_KERNEL::NormalizedCellType> sg;
7225 for(const int *i=connI;i!=connI+nbOfCells;)
7227 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7228 const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
7229 if(isTypeExists!=orderEnd)
7231 int pos=(int)std::distance(orderBg,isTypeExists);
7235 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7239 if(sg.find(curType)==sg.end())
7241 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7252 * This method returns 2 newly allocated DataArrayInt instances. The first is an array of size 'this->getNumberOfCells()' with one component,
7253 * 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
7254 * 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'.
7256 DataArrayInt *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayInt *&nbPerType) const
7258 checkConnectivityFullyDefined();
7259 int nbOfCells=getNumberOfCells();
7260 const int *conn=_nodal_connec->getConstPointer();
7261 const int *connI=_nodal_connec_index->getConstPointer();
7262 MCAuto<DataArrayInt> tmpa=DataArrayInt::New();
7263 MCAuto<DataArrayInt> tmpb=DataArrayInt::New();
7264 tmpa->alloc(nbOfCells,1);
7265 tmpb->alloc((int)std::distance(orderBg,orderEnd),1);
7266 tmpb->fillWithZero();
7267 int *tmp=tmpa->getPointer();
7268 int *tmp2=tmpb->getPointer();
7269 for(const int *i=connI;i!=connI+nbOfCells;i++)
7271 const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
7274 int pos=(int)std::distance(orderBg,where);
7276 tmp[std::distance(connI,i)]=pos;
7280 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
7281 std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
7282 oss << " has a type " << cm.getRepr() << " not in input array of type !";
7283 throw INTERP_KERNEL::Exception(oss.str().c_str());
7286 nbPerType=tmpb.retn();
7291 * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
7293 * \return a new object containing the old to new correspondance.
7295 * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
7297 DataArrayInt *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
7299 return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
7303 * 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.
7304 * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
7305 * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
7306 * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
7308 DataArrayInt *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
7310 DataArrayInt *nbPerType=0;
7311 MCAuto<DataArrayInt> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
7312 nbPerType->decrRef();
7313 return tmpa->buildPermArrPerLevel();
7317 * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
7318 * The number of cells remains unchanged after the call of this method.
7319 * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
7320 * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
7322 * \return the array giving the correspondance old to new.
7324 DataArrayInt *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
7326 checkFullyDefined();
7328 const int *conn=_nodal_connec->getConstPointer();
7329 const int *connI=_nodal_connec_index->getConstPointer();
7330 int nbOfCells=getNumberOfCells();
7331 std::vector<INTERP_KERNEL::NormalizedCellType> types;
7332 for(const int *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
7333 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
7335 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7336 types.push_back(curType);
7337 for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
7339 DataArrayInt *ret=DataArrayInt::New();
7340 ret->alloc(nbOfCells,1);
7341 int *retPtr=ret->getPointer();
7342 std::fill(retPtr,retPtr+nbOfCells,-1);
7344 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
7346 for(const int *i=connI;i!=connI+nbOfCells;i++)
7347 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
7348 retPtr[std::distance(connI,i)]=newCellId++;
7350 renumberCells(retPtr,false);
7355 * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
7356 * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
7357 * This method makes asumption that connectivity is correctly set before calling.
7359 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
7361 checkConnectivityFullyDefined();
7362 const int *conn=_nodal_connec->getConstPointer();
7363 const int *connI=_nodal_connec_index->getConstPointer();
7364 int nbOfCells=getNumberOfCells();
7365 std::vector<MEDCouplingUMesh *> ret;
7366 for(const int *i=connI;i!=connI+nbOfCells;)
7368 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7369 int beginCellId=(int)std::distance(connI,i);
7370 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7371 int endCellId=(int)std::distance(connI,i);
7372 int sz=endCellId-beginCellId;
7373 int *cells=new int[sz];
7374 for(int j=0;j<sz;j++)
7375 cells[j]=beginCellId+j;
7376 MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
7384 * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
7385 * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
7386 * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
7388 * \return a newly allocated instance, that the caller must manage.
7389 * \throw If \a this contains more than one geometric type.
7390 * \throw If the nodal connectivity of \a this is not fully defined.
7391 * \throw If the internal data is not coherent.
7393 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
7395 checkConnectivityFullyDefined();
7396 if(_types.size()!=1)
7397 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7398 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
7399 MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
7400 ret->setCoords(getCoords());
7401 MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
7404 MCAuto<DataArrayInt> c=convertNodalConnectivityToStaticGeoTypeMesh();
7405 retC->setNodalConnectivity(c);
7409 MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
7411 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
7412 DataArrayInt *c=0,*ci=0;
7413 convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
7414 MCAuto<DataArrayInt> cs(c),cis(ci);
7415 retD->setNodalConnectivity(cs,cis);
7420 DataArrayInt *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
7422 checkConnectivityFullyDefined();
7423 if(_types.size()!=1)
7424 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7425 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
7426 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
7429 std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
7430 oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
7431 throw INTERP_KERNEL::Exception(oss.str().c_str());
7433 int nbCells=getNumberOfCells();
7435 int nbNodesPerCell=(int)cm.getNumberOfNodes();
7436 MCAuto<DataArrayInt> connOut=DataArrayInt::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
7437 int *outPtr=connOut->getPointer();
7438 const int *conn=_nodal_connec->begin();
7439 const int *connI=_nodal_connec_index->begin();
7441 for(int i=0;i<nbCells;i++,connI++)
7443 if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
7444 outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
7447 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 << ") !";
7448 throw INTERP_KERNEL::Exception(oss.str().c_str());
7451 return connOut.retn();
7455 * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
7456 * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
7460 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayInt *&nodalConn, DataArrayInt *&nodalConnIndex) const
7462 static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
7463 checkConnectivityFullyDefined();
7464 if(_types.size()!=1)
7465 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7466 int nbCells=getNumberOfCells(),lgth=_nodal_connec->getNumberOfTuples();
7468 throw INTERP_KERNEL::Exception(msg0);
7469 MCAuto<DataArrayInt> c(DataArrayInt::New()),ci(DataArrayInt::New());
7470 c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
7471 int *cp(c->getPointer()),*cip(ci->getPointer());
7472 const int *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
7474 for(int i=0;i<nbCells;i++,cip++,incip++)
7476 int strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
7477 int delta(stop-strt);
7480 if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
7481 cp=std::copy(incp+strt,incp+stop,cp);
7483 throw INTERP_KERNEL::Exception(msg0);
7486 throw INTERP_KERNEL::Exception(msg0);
7487 cip[1]=cip[0]+delta;
7489 nodalConn=c.retn(); nodalConnIndex=ci.retn();
7493 * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
7494 * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
7495 * This method is particulary useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
7496 * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
7497 * are not used here to avoid the build of big permutation array.
7499 * \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
7500 * those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
7501 * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayInt instance whose number of tuples is equal to the number of chunks of same geotype
7502 * in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
7503 * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayInt instance having the same size than \b szOfCellGrpOfSameType. This
7504 * output array gives for each chunck of same type the corresponding mesh id in \b ms.
7505 * \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
7506 * is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
7508 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
7509 DataArrayInt *&szOfCellGrpOfSameType,
7510 DataArrayInt *&idInMsOfCellGrpOfSameType)
7512 std::vector<const MEDCouplingUMesh *> ms2;
7513 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
7516 (*it)->checkConnectivityFullyDefined();
7520 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
7521 const DataArrayDouble *refCoo=ms2[0]->getCoords();
7522 int meshDim=ms2[0]->getMeshDimension();
7523 std::vector<const MEDCouplingUMesh *> m1ssm;
7524 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
7526 std::vector<const MEDCouplingUMesh *> m1ssmSingle;
7527 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
7529 MCAuto<DataArrayInt> ret1(DataArrayInt::New()),ret2(DataArrayInt::New());
7530 ret1->alloc(0,1); ret2->alloc(0,1);
7531 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
7533 if(meshDim!=(*it)->getMeshDimension())
7534 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
7535 if(refCoo!=(*it)->getCoords())
7536 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
7537 std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
7538 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
7539 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
7540 for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
7542 MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
7543 m1ssmSingleAuto.push_back(singleCell);
7544 m1ssmSingle.push_back(singleCell);
7545 ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
7548 MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
7549 MCAuto<DataArrayInt> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
7550 std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
7551 for(std::size_t i=0;i<m1ssm.size();i++)
7552 m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
7553 MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
7554 szOfCellGrpOfSameType=ret1->renumber(renum->getConstPointer());
7555 idInMsOfCellGrpOfSameType=ret2->renumber(renum->getConstPointer());
7560 * This method returns a newly created DataArrayInt instance.
7561 * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
7563 DataArrayInt *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const int *begin, const int *end) const
7565 checkFullyDefined();
7566 const int *conn=_nodal_connec->getConstPointer();
7567 const int *connIndex=_nodal_connec_index->getConstPointer();
7568 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
7569 for(const int *w=begin;w!=end;w++)
7570 if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
7571 ret->pushBackSilent(*w);
7576 * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
7577 * are in [0:getNumberOfCells())
7579 DataArrayInt *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayInt *da) const
7581 checkFullyDefined();
7582 const int *conn=_nodal_connec->getConstPointer();
7583 const int *connI=_nodal_connec_index->getConstPointer();
7584 int nbOfCells=getNumberOfCells();
7585 std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
7586 int *tmp=new int[nbOfCells];
7587 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
7590 for(const int *i=connI;i!=connI+nbOfCells;i++)
7591 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
7592 tmp[std::distance(connI,i)]=j++;
7594 DataArrayInt *ret=DataArrayInt::New();
7595 ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
7596 ret->copyStringInfoFrom(*da);
7597 int *retPtr=ret->getPointer();
7598 const int *daPtr=da->getConstPointer();
7599 int nbOfElems=da->getNbOfElems();
7600 for(int k=0;k<nbOfElems;k++)
7601 retPtr[k]=tmp[daPtr[k]];
7607 * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
7608 * This method \b works \b for mesh sorted by type.
7609 * cells whose ids is in 'idsPerGeoType' array.
7610 * This method conserves coords and name of mesh.
7612 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const int *idsPerGeoTypeBg, const int *idsPerGeoTypeEnd) const
7614 std::vector<int> code=getDistributionOfTypes();
7615 std::size_t nOfTypesInThis=code.size()/3;
7616 int sz=0,szOfType=0;
7617 for(std::size_t i=0;i<nOfTypesInThis;i++)
7622 szOfType=code[3*i+1];
7624 for(const int *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
7625 if(*work<0 || *work>=szOfType)
7627 std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
7628 oss << ". It should be in [0," << szOfType << ") !";
7629 throw INTERP_KERNEL::Exception(oss.str().c_str());
7631 MCAuto<DataArrayInt> idsTokeep=DataArrayInt::New(); idsTokeep->alloc(sz+(int)std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
7632 int *idsPtr=idsTokeep->getPointer();
7634 for(std::size_t i=0;i<nOfTypesInThis;i++)
7637 for(int j=0;j<code[3*i+1];j++)
7640 idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind2nd(std::plus<int>(),offset));
7641 offset+=code[3*i+1];
7643 MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
7644 ret->copyTinyInfoFrom(this);
7649 * This method returns a vector of size 'this->getNumberOfCells()'.
7650 * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
7652 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
7654 int ncell=getNumberOfCells();
7655 std::vector<bool> ret(ncell);
7656 const int *cI=getNodalConnectivityIndex()->getConstPointer();
7657 const int *c=getNodalConnectivity()->getConstPointer();
7658 for(int i=0;i<ncell;i++)
7660 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
7661 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
7662 ret[i]=cm.isQuadratic();
7668 * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
7670 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
7672 if(other->getType()!=UNSTRUCTURED)
7673 throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
7674 const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
7675 return MergeUMeshes(this,otherC);
7679 * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
7680 * computed by averaging coordinates of cell nodes, so this method is not a right
7681 * choice for degnerated meshes (not well oriented, cells with measure close to zero).
7682 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
7683 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
7684 * components. The caller is to delete this array using decrRef() as it is
7686 * \throw If the coordinates array is not set.
7687 * \throw If the nodal connectivity of cells is not defined.
7688 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
7690 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
7692 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
7693 int spaceDim=getSpaceDimension();
7694 int nbOfCells=getNumberOfCells();
7695 ret->alloc(nbOfCells,spaceDim);
7696 ret->copyStringInfoFrom(*getCoords());
7697 double *ptToFill=ret->getPointer();
7698 const int *nodal=_nodal_connec->getConstPointer();
7699 const int *nodalI=_nodal_connec_index->getConstPointer();
7700 const double *coor=_coords->getConstPointer();
7701 for(int i=0;i<nbOfCells;i++)
7703 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
7704 INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
7711 * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
7712 * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
7714 * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
7715 * DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
7717 * \sa MEDCouplingUMesh::computeCellCenterOfMass
7718 * \throw If \a this is not fully defined (coordinates and connectivity)
7719 * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
7721 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
7723 checkFullyDefined();
7724 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
7725 int spaceDim=getSpaceDimension();
7726 int nbOfCells=getNumberOfCells();
7727 int nbOfNodes=getNumberOfNodes();
7728 ret->alloc(nbOfCells,spaceDim);
7729 double *ptToFill=ret->getPointer();
7730 const int *nodal=_nodal_connec->getConstPointer();
7731 const int *nodalI=_nodal_connec_index->getConstPointer();
7732 const double *coor=_coords->getConstPointer();
7733 for(int i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
7735 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
7736 std::fill(ptToFill,ptToFill+spaceDim,0.);
7737 if(type!=INTERP_KERNEL::NORM_POLYHED)
7739 for(const int *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
7741 if(*conn>=0 && *conn<nbOfNodes)
7742 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
7745 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," << nbOfNodes << ") !";
7746 throw INTERP_KERNEL::Exception(oss.str().c_str());
7749 int nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
7750 if(nbOfNodesInCell>0)
7751 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
7754 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
7755 throw INTERP_KERNEL::Exception(oss.str().c_str());
7760 std::set<int> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
7762 for(std::set<int>::const_iterator it=s.begin();it!=s.end();it++)
7764 if(*it>=0 && *it<nbOfNodes)
7765 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
7768 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," << nbOfNodes << ") !";
7769 throw INTERP_KERNEL::Exception(oss.str().c_str());
7773 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)s.size()));
7776 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
7777 throw INTERP_KERNEL::Exception(oss.str().c_str());
7785 * Returns a new DataArrayDouble holding barycenters of specified cells. The
7786 * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
7787 * are specified via an array of cell ids.
7788 * \warning Validity of the specified cell ids is not checked!
7789 * Valid range is [ 0, \a this->getNumberOfCells() ).
7790 * \param [in] begin - an array of cell ids of interest.
7791 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
7792 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
7793 * end - \a begin ) tuples per \a this->getSpaceDimension() components. The
7794 * caller is to delete this array using decrRef() as it is no more needed.
7795 * \throw If the coordinates array is not set.
7796 * \throw If the nodal connectivity of cells is not defined.
7798 * \if ENABLE_EXAMPLES
7799 * \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
7800 * \ref py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
7803 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const int *begin, const int *end) const
7805 DataArrayDouble *ret=DataArrayDouble::New();
7806 int spaceDim=getSpaceDimension();
7807 int nbOfTuple=(int)std::distance(begin,end);
7808 ret->alloc(nbOfTuple,spaceDim);
7809 double *ptToFill=ret->getPointer();
7810 double *tmp=new double[spaceDim];
7811 const int *nodal=_nodal_connec->getConstPointer();
7812 const int *nodalI=_nodal_connec_index->getConstPointer();
7813 const double *coor=_coords->getConstPointer();
7814 for(const int *w=begin;w!=end;w++)
7816 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
7817 INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
7825 * 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".
7826 * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
7827 * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
7828 * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
7829 * This method is useful to detect 2D cells in 3D space that are not coplanar.
7831 * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
7832 * \throw If spaceDim!=3 or meshDim!=2.
7833 * \throw If connectivity of \a this is invalid.
7834 * \throw If connectivity of a cell in \a this points to an invalid node.
7836 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
7838 MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
7839 int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
7840 if(getSpaceDimension()!=3 || getMeshDimension()!=2)
7841 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
7842 ret->alloc(nbOfCells,4);
7843 double *retPtr(ret->getPointer());
7844 const int *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
7845 const double *coor(_coords->begin());
7846 for(int i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
7848 double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
7849 if(nodalI[1]-nodalI[0]>=3)
7851 for(int j=0;j<3;j++)
7853 int nodeId(nodal[nodalI[0]+1+j]);
7854 if(nodeId>=0 && nodeId<nbOfNodes)
7855 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
7858 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
7859 throw INTERP_KERNEL::Exception(oss.str().c_str());
7865 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
7866 throw INTERP_KERNEL::Exception(oss.str().c_str());
7868 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
7869 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
7875 * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
7878 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
7881 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
7882 da->checkAllocated();
7883 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(da->getName(),0);
7885 int nbOfTuples=da->getNumberOfTuples();
7886 MCAuto<DataArrayInt> c=DataArrayInt::New();
7887 MCAuto<DataArrayInt> cI=DataArrayInt::New();
7888 c->alloc(2*nbOfTuples,1);
7889 cI->alloc(nbOfTuples+1,1);
7890 int *cp=c->getPointer();
7891 int *cip=cI->getPointer();
7893 for(int i=0;i<nbOfTuples;i++)
7895 *cp++=INTERP_KERNEL::NORM_POINT1;
7899 ret->setConnectivity(c,cI,true);
7903 * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
7904 * Cells and nodes of
7905 * the first mesh precede cells and nodes of the second mesh within the result mesh.
7906 * \param [in] mesh1 - the first mesh.
7907 * \param [in] mesh2 - the second mesh.
7908 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7909 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7910 * is no more needed.
7911 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
7912 * \throw If the coordinates array is not set in none of the meshes.
7913 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
7914 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
7916 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
7918 std::vector<const MEDCouplingUMesh *> tmp(2);
7919 tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
7920 return MergeUMeshes(tmp);
7924 * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
7925 * Cells and nodes of
7926 * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
7927 * \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
7928 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7929 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7930 * is no more needed.
7931 * \throw If \a a.size() == 0.
7932 * \throw If \a a[ *i* ] == NULL.
7933 * \throw If the coordinates array is not set in none of the meshes.
7934 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
7935 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
7937 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(std::vector<const MEDCouplingUMesh *>& a)
7939 std::size_t sz=a.size();
7941 return MergeUMeshesLL(a);
7942 for(std::size_t ii=0;ii<sz;ii++)
7945 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
7946 throw INTERP_KERNEL::Exception(oss.str().c_str());
7948 std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
7949 std::vector< const MEDCouplingUMesh * > aa(sz);
7951 for(std::size_t i=0;i<sz && spaceDim==-3;i++)
7953 const MEDCouplingUMesh *cur=a[i];
7954 const DataArrayDouble *coo=cur->getCoords();
7956 spaceDim=coo->getNumberOfComponents();
7959 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
7960 for(std::size_t i=0;i<sz;i++)
7962 bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
7965 return MergeUMeshesLL(aa);
7970 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesLL(std::vector<const MEDCouplingUMesh *>& a)
7973 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : input array must be NON EMPTY !");
7974 std::vector<const MEDCouplingUMesh *>::const_iterator it=a.begin();
7975 int meshDim=(*it)->getMeshDimension();
7976 int nbOfCells=(*it)->getNumberOfCells();
7977 int meshLgth=(*it++)->getNodalConnectivityArrayLen();
7978 for(;it!=a.end();it++)
7980 if(meshDim!=(*it)->getMeshDimension())
7981 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, MergeUMeshes impossible !");
7982 nbOfCells+=(*it)->getNumberOfCells();
7983 meshLgth+=(*it)->getNodalConnectivityArrayLen();
7985 std::vector<const MEDCouplingPointSet *> aps(a.size());
7986 std::copy(a.begin(),a.end(),aps.begin());
7987 MCAuto<DataArrayDouble> pts=MergeNodesArray(aps);
7988 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("merge",meshDim);
7989 ret->setCoords(pts);
7990 MCAuto<DataArrayInt> c=DataArrayInt::New();
7991 c->alloc(meshLgth,1);
7992 int *cPtr=c->getPointer();
7993 MCAuto<DataArrayInt> cI=DataArrayInt::New();
7994 cI->alloc(nbOfCells+1,1);
7995 int *cIPtr=cI->getPointer();
7999 for(it=a.begin();it!=a.end();it++)
8001 int curNbOfCell=(*it)->getNumberOfCells();
8002 const int *curCI=(*it)->_nodal_connec_index->getConstPointer();
8003 const int *curC=(*it)->_nodal_connec->getConstPointer();
8004 cIPtr=std::transform(curCI+1,curCI+curNbOfCell+1,cIPtr,std::bind2nd(std::plus<int>(),offset));
8005 for(int j=0;j<curNbOfCell;j++)
8007 const int *src=curC+curCI[j];
8009 for(;src!=curC+curCI[j+1];src++,cPtr++)
8017 offset+=curCI[curNbOfCell];
8018 offset2+=(*it)->getNumberOfNodes();
8021 ret->setConnectivity(c,cI,true);
8028 * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
8029 * dimension and sharing the node coordinates array.
8030 * All cells of the first mesh precede all cells of the second mesh
8031 * within the result mesh.
8032 * \param [in] mesh1 - the first mesh.
8033 * \param [in] mesh2 - the second mesh.
8034 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8035 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8036 * is no more needed.
8037 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
8038 * \throw If the meshes do not share the node coordinates array.
8039 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
8040 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
8042 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
8044 std::vector<const MEDCouplingUMesh *> tmp(2);
8045 tmp[0]=mesh1; tmp[1]=mesh2;
8046 return MergeUMeshesOnSameCoords(tmp);
8050 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
8051 * dimension and sharing the node coordinates array.
8052 * All cells of the *i*-th mesh precede all cells of the
8053 * (*i*+1)-th mesh within the result mesh.
8054 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
8055 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8056 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8057 * is no more needed.
8058 * \throw If \a a.size() == 0.
8059 * \throw If \a a[ *i* ] == NULL.
8060 * \throw If the meshes do not share the node coordinates array.
8061 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
8062 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
8064 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
8067 throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
8068 for(std::size_t ii=0;ii<meshes.size();ii++)
8071 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
8072 throw INTERP_KERNEL::Exception(oss.str().c_str());
8074 const DataArrayDouble *coords=meshes.front()->getCoords();
8075 int meshDim=meshes.front()->getMeshDimension();
8076 std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
8078 int meshIndexLgth=0;
8079 for(;iter!=meshes.end();iter++)
8081 if(coords!=(*iter)->getCoords())
8082 throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
8083 if(meshDim!=(*iter)->getMeshDimension())
8084 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
8085 meshLgth+=(*iter)->getNodalConnectivityArrayLen();
8086 meshIndexLgth+=(*iter)->getNumberOfCells();
8088 MCAuto<DataArrayInt> nodal=DataArrayInt::New();
8089 nodal->alloc(meshLgth,1);
8090 int *nodalPtr=nodal->getPointer();
8091 MCAuto<DataArrayInt> nodalIndex=DataArrayInt::New();
8092 nodalIndex->alloc(meshIndexLgth+1,1);
8093 int *nodalIndexPtr=nodalIndex->getPointer();
8095 for(iter=meshes.begin();iter!=meshes.end();iter++)
8097 const int *nod=(*iter)->getNodalConnectivity()->getConstPointer();
8098 const int *index=(*iter)->getNodalConnectivityIndex()->getConstPointer();
8099 int nbOfCells=(*iter)->getNumberOfCells();
8100 int meshLgth2=(*iter)->getNodalConnectivityArrayLen();
8101 nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
8102 if(iter!=meshes.begin())
8103 nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind2nd(std::plus<int>(),offset));
8105 nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
8108 MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
8109 ret->setName("merge");
8110 ret->setMeshDimension(meshDim);
8111 ret->setConnectivity(nodal,nodalIndex,true);
8112 ret->setCoords(coords);
8117 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
8118 * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
8119 * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
8120 * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
8121 * New" mode are returned for each input mesh.
8122 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
8123 * \param [in] compType - specifies a cell comparison technique. For meaning of its
8124 * valid values [0,1,2], see zipConnectivityTraducer().
8125 * \param [in,out] corr - an array of DataArrayInt, of the same size as \a
8126 * meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
8127 * mesh. The caller is to delete each of the arrays using decrRef() as it is
8129 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8130 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8131 * is no more needed.
8132 * \throw If \a meshes.size() == 0.
8133 * \throw If \a meshes[ *i* ] == NULL.
8134 * \throw If the meshes do not share the node coordinates array.
8135 * \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
8136 * \throw If the \a meshes are of different dimension (getMeshDimension()).
8137 * \throw If the nodal connectivity of cells of any of \a meshes is not defined.
8138 * \throw If the nodal connectivity any of \a meshes includes an invalid id.
8140 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayInt *>& corr)
8142 //All checks are delegated to MergeUMeshesOnSameCoords
8143 MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
8144 MCAuto<DataArrayInt> o2n=ret->zipConnectivityTraducer(compType);
8145 corr.resize(meshes.size());
8146 std::size_t nbOfMeshes=meshes.size();
8148 const int *o2nPtr=o2n->getConstPointer();
8149 for(std::size_t i=0;i<nbOfMeshes;i++)
8151 DataArrayInt *tmp=DataArrayInt::New();
8152 int curNbOfCells=meshes[i]->getNumberOfCells();
8153 tmp->alloc(curNbOfCells,1);
8154 std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
8155 offset+=curNbOfCells;
8156 tmp->setName(meshes[i]->getName());
8163 * Makes all given meshes share the nodal connectivity array. The common connectivity
8164 * array is created by concatenating the connectivity arrays of all given meshes. All
8165 * the given meshes must be of the same space dimension but dimension of cells **can
8166 * differ**. This method is particulary useful in MEDLoader context to build a \ref
8167 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
8168 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
8169 * \param [in,out] meshes - a vector of meshes to update.
8170 * \throw If any of \a meshes is NULL.
8171 * \throw If the coordinates array is not set in any of \a meshes.
8172 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
8173 * \throw If \a meshes are of different space dimension.
8175 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
8177 std::size_t sz=meshes.size();
8180 std::vector< const DataArrayDouble * > coords(meshes.size());
8181 std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
8182 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
8186 (*it)->checkConnectivityFullyDefined();
8187 const DataArrayDouble *coo=(*it)->getCoords();
8192 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
8193 oss << " has no coordinate array defined !";
8194 throw INTERP_KERNEL::Exception(oss.str().c_str());
8199 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
8200 oss << " is null !";
8201 throw INTERP_KERNEL::Exception(oss.str().c_str());
8204 MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
8205 std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
8206 int offset=(*it)->getNumberOfNodes();
8207 (*it++)->setCoords(res);
8208 for(;it!=meshes.end();it++)
8210 int oldNumberOfNodes=(*it)->getNumberOfNodes();
8211 (*it)->setCoords(res);
8212 (*it)->shiftNodeNumbersInConn(offset);
8213 offset+=oldNumberOfNodes;
8218 * Merges nodes coincident with a given precision within all given meshes that share
8219 * the nodal connectivity array. The given meshes **can be of different** mesh
8220 * dimension. This method is particulary useful in MEDLoader context to build a \ref
8221 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
8222 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
8223 * \param [in,out] meshes - a vector of meshes to update.
8224 * \param [in] eps - the precision used to detect coincident nodes (infinite norm).
8225 * \throw If any of \a meshes is NULL.
8226 * \throw If the \a meshes do not share the same node coordinates array.
8227 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
8229 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
8233 std::set<const DataArrayDouble *> s;
8234 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
8237 s.insert((*it)->getCoords());
8240 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 !";
8241 throw INTERP_KERNEL::Exception(oss.str().c_str());
8246 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 !";
8247 throw INTERP_KERNEL::Exception(oss.str().c_str());
8249 const DataArrayDouble *coo=*(s.begin());
8253 DataArrayInt *comm,*commI;
8254 coo->findCommonTuples(eps,-1,comm,commI);
8255 MCAuto<DataArrayInt> tmp1(comm),tmp2(commI);
8256 int oldNbOfNodes=coo->getNumberOfTuples();
8258 MCAuto<DataArrayInt> o2n=DataArrayInt::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
8259 if(oldNbOfNodes==newNbOfNodes)
8261 MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->getConstPointer(),newNbOfNodes);
8262 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
8264 (*it)->renumberNodesInConn(o2n->getConstPointer());
8265 (*it)->setCoords(newCoords);
8270 * 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.
8271 * \param nbOfNodesPerLev in parameter that specifies the number of nodes of one slice of global dataset
8272 * \param isQuad specifies the policy of connectivity.
8273 * @ret in/out parameter in which the result will be append
8275 void MEDCouplingUMesh::AppendExtrudedCell(const int *connBg, const int *connEnd, int nbOfNodesPerLev, bool isQuad, std::vector<int>& ret)
8277 INTERP_KERNEL::NormalizedCellType flatType=(INTERP_KERNEL::NormalizedCellType)connBg[0];
8278 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(flatType);
8279 ret.push_back(cm.getExtrudedType());
8280 int deltaz=isQuad?2*nbOfNodesPerLev:nbOfNodesPerLev;
8283 case INTERP_KERNEL::NORM_POINT1:
8285 ret.push_back(connBg[1]);
8286 ret.push_back(connBg[1]+nbOfNodesPerLev);
8289 case INTERP_KERNEL::NORM_SEG2:
8291 int conn[4]={connBg[1],connBg[2],connBg[2]+deltaz,connBg[1]+deltaz};
8292 ret.insert(ret.end(),conn,conn+4);
8295 case INTERP_KERNEL::NORM_SEG3:
8297 int conn[8]={connBg[1],connBg[3],connBg[3]+deltaz,connBg[1]+deltaz,connBg[2],connBg[3]+nbOfNodesPerLev,connBg[2]+deltaz,connBg[1]+nbOfNodesPerLev};
8298 ret.insert(ret.end(),conn,conn+8);
8301 case INTERP_KERNEL::NORM_QUAD4:
8303 int conn[8]={connBg[1],connBg[2],connBg[3],connBg[4],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4]+deltaz};
8304 ret.insert(ret.end(),conn,conn+8);
8307 case INTERP_KERNEL::NORM_TRI3:
8309 int conn[6]={connBg[1],connBg[2],connBg[3],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz};
8310 ret.insert(ret.end(),conn,conn+6);
8313 case INTERP_KERNEL::NORM_TRI6:
8315 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,
8316 connBg[1]+nbOfNodesPerLev,connBg[2]+nbOfNodesPerLev,connBg[3]+nbOfNodesPerLev};
8317 ret.insert(ret.end(),conn,conn+15);
8320 case INTERP_KERNEL::NORM_QUAD8:
8323 connBg[1],connBg[2],connBg[3],connBg[4],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4]+deltaz,
8324 connBg[5],connBg[6],connBg[7],connBg[8],connBg[5]+deltaz,connBg[6]+deltaz,connBg[7]+deltaz,connBg[8]+deltaz,
8325 connBg[1]+nbOfNodesPerLev,connBg[2]+nbOfNodesPerLev,connBg[3]+nbOfNodesPerLev,connBg[4]+nbOfNodesPerLev
8327 ret.insert(ret.end(),conn,conn+20);
8330 case INTERP_KERNEL::NORM_POLYGON:
8332 std::back_insert_iterator< std::vector<int> > ii(ret);
8333 std::copy(connBg+1,connEnd,ii);
8335 std::reverse_iterator<const int *> rConnBg(connEnd);
8336 std::reverse_iterator<const int *> rConnEnd(connBg+1);
8337 std::transform(rConnBg,rConnEnd,ii,std::bind2nd(std::plus<int>(),deltaz));
8338 std::size_t nbOfRadFaces=std::distance(connBg+1,connEnd);
8339 for(std::size_t i=0;i<nbOfRadFaces;i++)
8342 int conn[4]={connBg[(i+1)%nbOfRadFaces+1],connBg[i+1],connBg[i+1]+deltaz,connBg[(i+1)%nbOfRadFaces+1]+deltaz};
8343 std::copy(conn,conn+4,ii);
8348 throw INTERP_KERNEL::Exception("A flat type has been detected that has not its extruded representation !");
8353 * This static operates only for coords in 3D. The polygon is specfied by its connectivity nodes in [ \a begin , \a end ).
8355 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const int *begin, const int *end, const double *coords)
8358 double v[3]={0.,0.,0.};
8359 std::size_t sz=std::distance(begin,end);
8364 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];
8365 v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
8366 v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
8368 double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
8370 // Try using quadratic points if standard points are degenerated (for example a QPOLYG with two
8371 // SEG3 forming a circle):
8372 if (fabs(ret) < INTERP_KERNEL::DEFAULT_ABS_TOL && isQuadratic)
8374 v[0] = 0.0; v[1] = 0.0; v[2] = 0.0;
8375 for(std::size_t j=0;j<sz;j++)
8377 if (j%2) // current point i is quadratic, next point i+1 is standard
8380 ip1 = (j+1)%sz; // ip1 = "i+1"
8382 else // current point i is standard, next point i+1 is quadratic
8387 v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
8388 v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
8389 v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
8391 ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
8397 * The polyhedron is specfied by its connectivity nodes in [ \a begin , \a end ).
8399 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const int *begin, const int *end, const double *coords)
8401 std::vector<std::pair<int,int> > edges;
8402 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
8403 const int *bgFace=begin;
8404 for(std::size_t i=0;i<nbOfFaces;i++)
8406 const int *endFace=std::find(bgFace+1,end,-1);
8407 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
8408 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8410 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8411 if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
8413 edges.push_back(p1);
8417 return INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)>-EPS_FOR_POLYH_ORIENTATION;
8421 * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
8423 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const int *begin, const int *end, const double *coords)
8425 double vec0[3],vec1[3];
8426 std::size_t sz=std::distance(begin,end);
8428 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
8429 int nbOfNodes=(int)sz/2;
8430 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
8431 const double *pt0=coords+3*begin[0];
8432 const double *pt1=coords+3*begin[nbOfNodes];
8433 vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
8434 return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
8437 void MEDCouplingUMesh::CorrectExtrudedStaticCell(int *begin, int *end)
8439 std::size_t sz=std::distance(begin,end);
8440 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
8441 std::size_t nbOfNodes(sz/2);
8442 std::copy(begin,end,(int *)tmp);
8443 for(std::size_t j=1;j<nbOfNodes;j++)
8445 begin[j]=tmp[nbOfNodes-j];
8446 begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
8450 bool MEDCouplingUMesh::IsTetra4WellOriented(const int *begin, const int *end, const double *coords)
8452 std::size_t sz=std::distance(begin,end);
8454 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
8455 double vec0[3],vec1[3];
8456 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
8457 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];
8458 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;
8461 bool MEDCouplingUMesh::IsPyra5WellOriented(const int *begin, const int *end, const double *coords)
8463 std::size_t sz=std::distance(begin,end);
8465 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
8467 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
8468 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
8469 return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
8473 * 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 )
8474 * 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
8477 * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
8478 * \param [in] coords the coordinates with nb of components exactly equal to 3
8479 * \param [in] begin begin of the nodal connectivity (geometric type included) of a single polyhedron cell
8480 * \param [in] end end of nodal connectivity of a single polyhedron cell (excluded)
8481 * \param [out] res the result is put at the end of the vector without any alteration of the data.
8483 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, const int *begin, const int *end, DataArrayInt *res)
8485 int nbFaces=std::count(begin+1,end,-1)+1;
8486 MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
8487 double *vPtr=v->getPointer();
8488 MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,1);
8489 double *pPtr=p->getPointer();
8490 const int *stFaceConn=begin+1;
8491 for(int i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
8493 const int *endFaceConn=std::find(stFaceConn,end,-1);
8494 ComputeVecAndPtOfFace(eps,coords->getConstPointer(),stFaceConn,endFaceConn,vPtr,pPtr);
8495 stFaceConn=endFaceConn+1;
8497 pPtr=p->getPointer(); vPtr=v->getPointer();
8498 DataArrayInt *comm1=0,*commI1=0;
8499 v->findCommonTuples(eps,-1,comm1,commI1);
8500 MCAuto<DataArrayInt> comm1Auto(comm1),commI1Auto(commI1);
8501 const int *comm1Ptr=comm1->getConstPointer();
8502 const int *commI1Ptr=commI1->getConstPointer();
8503 int nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
8504 res->pushBackSilent((int)INTERP_KERNEL::NORM_POLYHED);
8506 MCAuto<MEDCouplingUMesh> mm=MEDCouplingUMesh::New("",3);
8507 mm->setCoords(const_cast<DataArrayDouble *>(coords)); mm->allocateCells(1); mm->insertNextCell(INTERP_KERNEL::NORM_POLYHED,(int)std::distance(begin+1,end),begin+1);
8508 mm->finishInsertingCells();
8510 for(int i=0;i<nbOfGrps1;i++)
8512 int vecId=comm1Ptr[commI1Ptr[i]];
8513 MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
8514 DataArrayInt *comm2=0,*commI2=0;
8515 tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
8516 MCAuto<DataArrayInt> comm2Auto(comm2),commI2Auto(commI2);
8517 const int *comm2Ptr=comm2->getConstPointer();
8518 const int *commI2Ptr=commI2->getConstPointer();
8519 int nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
8520 for(int j=0;j<nbOfGrps2;j++)
8522 if(commI2Ptr[j+1]-commI2Ptr[j]<=1)
8524 res->insertAtTheEnd(begin,end);
8525 res->pushBackSilent(-1);
8529 int pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
8530 MCAuto<DataArrayInt> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
8531 ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
8532 DataArrayInt *tmp0=DataArrayInt::New(),*tmp1=DataArrayInt::New(),*tmp2=DataArrayInt::New(),*tmp3=DataArrayInt::New();
8533 MCAuto<MEDCouplingUMesh> mm2=mm->buildDescendingConnectivity(tmp0,tmp1,tmp2,tmp3); tmp0->decrRef(); tmp1->decrRef(); tmp2->decrRef(); tmp3->decrRef();
8534 MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(mm2->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
8535 MCAuto<DataArrayInt> idsNodeTmp=mm3->zipCoordsTraducer();
8536 MCAuto<DataArrayInt> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
8537 const int *idsNodePtr=idsNode->getConstPointer();
8538 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];
8539 double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
8540 double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
8541 if(std::abs(norm)>eps)
8543 double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
8544 mm3->rotate(center,vec,angle);
8546 mm3->changeSpaceDimension(2);
8547 MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
8548 const int *conn4=mm4->getNodalConnectivity()->getConstPointer();
8549 const int *connI4=mm4->getNodalConnectivityIndex()->getConstPointer();
8550 int nbOfCells=mm4->getNumberOfCells();
8551 for(int k=0;k<nbOfCells;k++)
8554 for(const int *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
8555 res->pushBackSilent(idsNodePtr[*work]);
8556 res->pushBackSilent(-1);
8561 res->popBackSilent();
8565 * 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
8566 * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
8568 * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
8569 * \param [in] coords coordinates expected to have 3 components.
8570 * \param [in] begin start of the nodal connectivity of the face.
8571 * \param [in] end end of the nodal connectivity (excluded) of the face.
8572 * \param [out] v the normalized vector of size 3
8573 * \param [out] p the pos of plane
8575 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const int *begin, const int *end, double *v, double *p)
8577 std::size_t nbPoints=std::distance(begin,end);
8579 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
8580 double vec[3]={0.,0.,0.};
8582 bool refFound=false;
8583 for(;j<nbPoints-1 && !refFound;j++)
8585 vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
8586 vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
8587 vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
8588 double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
8592 vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
8595 for(std::size_t i=j;i<nbPoints-1;i++)
8598 curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
8599 curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
8600 curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
8601 double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
8604 curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
8605 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];
8606 norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
8609 v[0]/=norm; v[1]/=norm; v[2]/=norm;
8610 *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
8614 throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
8618 * This method tries to obtain a well oriented polyhedron.
8619 * If the algorithm fails, an exception will be thrown.
8621 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(int *begin, int *end, const double *coords)
8623 std::list< std::pair<int,int> > edgesOK,edgesFinished;
8624 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
8625 std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
8627 int *bgFace=begin,*endFace=std::find(begin+1,end,-1);
8628 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
8629 for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<int,int> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
8631 while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
8634 std::size_t smthChanged=0;
8635 for(std::size_t i=0;i<nbOfFaces;i++)
8637 endFace=std::find(bgFace+1,end,-1);
8638 nbOfEdgesInFace=std::distance(bgFace,endFace);
8642 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8644 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8645 std::pair<int,int> p2(p1.second,p1.first);
8646 bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
8647 bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
8648 if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
8653 std::reverse(bgFace+1,endFace);
8654 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8656 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8657 std::pair<int,int> p2(p1.second,p1.first);
8658 if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
8659 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str().c_str()); }
8660 if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
8661 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str().c_str()); }
8662 std::list< std::pair<int,int> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
8663 if(it!=edgesOK.end())
8666 edgesFinished.push_back(p1);
8669 edgesOK.push_back(p1);
8676 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
8678 if(!edgesOK.empty())
8679 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
8680 if(INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)<-EPS_FOR_POLYH_ORIENTATION)
8681 {//not lucky ! The first face was not correctly oriented : reorient all faces...
8683 for(std::size_t i=0;i<nbOfFaces;i++)
8685 endFace=std::find(bgFace+1,end,-1);
8686 std::reverse(bgFace+1,endFace);
8692 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMeshLinear(const MEDCouplingUMesh *skin, const DataArrayInt *n2o) const
8694 int nbOfNodesExpected(skin->getNumberOfNodes());
8695 const int *n2oPtr(n2o->getConstPointer());
8696 MCAuto<DataArrayInt> revNodal(DataArrayInt::New()),revNodalI(DataArrayInt::New());
8697 skin->getReverseNodalConnectivity(revNodal,revNodalI);
8698 const int *revNodalPtr(revNodal->getConstPointer()),*revNodalIPtr(revNodalI->getConstPointer());
8699 const int *nodalPtr(skin->getNodalConnectivity()->getConstPointer());
8700 const int *nodalIPtr(skin->getNodalConnectivityIndex()->getConstPointer());
8701 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfNodesExpected+1,1);
8702 int *work(ret->getPointer()); *work++=INTERP_KERNEL::NORM_POLYGON;
8703 if(nbOfNodesExpected<1)
8705 int prevCell(0),prevNode(nodalPtr[nodalIPtr[0]+1]);
8706 *work++=n2oPtr[prevNode];
8707 for(int i=1;i<nbOfNodesExpected;i++)
8709 if(nodalIPtr[prevCell+1]-nodalIPtr[prevCell]==3)
8711 std::set<int> conn(nodalPtr+nodalIPtr[prevCell]+1,nodalPtr+nodalIPtr[prevCell]+3);
8712 conn.erase(prevNode);
8715 int curNode(*(conn.begin()));
8716 *work++=n2oPtr[curNode];
8717 std::set<int> shar(revNodalPtr+revNodalIPtr[curNode],revNodalPtr+revNodalIPtr[curNode+1]);
8718 shar.erase(prevCell);
8721 prevCell=*(shar.begin());
8725 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected 2 !");
8728 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected 1 !");
8731 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected cell !");
8736 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMeshQuadratic(const MEDCouplingUMesh *skin, const DataArrayInt *n2o) const
8738 int nbOfNodesExpected(skin->getNumberOfNodes());
8739 int nbOfTurn(nbOfNodesExpected/2);
8740 const int *n2oPtr(n2o->getConstPointer());
8741 MCAuto<DataArrayInt> revNodal(DataArrayInt::New()),revNodalI(DataArrayInt::New());
8742 skin->getReverseNodalConnectivity(revNodal,revNodalI);
8743 const int *revNodalPtr(revNodal->getConstPointer()),*revNodalIPtr(revNodalI->getConstPointer());
8744 const int *nodalPtr(skin->getNodalConnectivity()->getConstPointer());
8745 const int *nodalIPtr(skin->getNodalConnectivityIndex()->getConstPointer());
8746 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfNodesExpected+1,1);
8747 int *work(ret->getPointer()); *work++=INTERP_KERNEL::NORM_QPOLYG;
8748 if(nbOfNodesExpected<1)
8750 int prevCell(0),prevNode(nodalPtr[nodalIPtr[0]+1]);
8751 *work=n2oPtr[prevNode]; work[nbOfTurn]=n2oPtr[nodalPtr[nodalIPtr[0]+3]]; work++;
8752 for(int i=1;i<nbOfTurn;i++)
8754 if(nodalIPtr[prevCell+1]-nodalIPtr[prevCell]==4)
8756 std::set<int> conn(nodalPtr+nodalIPtr[prevCell]+1,nodalPtr+nodalIPtr[prevCell]+3);
8757 conn.erase(prevNode);
8760 int curNode(*(conn.begin()));
8761 *work=n2oPtr[curNode];
8762 std::set<int> shar(revNodalPtr+revNodalIPtr[curNode],revNodalPtr+revNodalIPtr[curNode+1]);
8763 shar.erase(prevCell);
8766 int curCell(*(shar.begin()));
8767 work[nbOfTurn]=n2oPtr[nodalPtr[nodalIPtr[curCell]+3]];
8773 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected 2 !");
8776 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected 1 !");
8779 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected cell !");
8785 * This method makes the assumption spacedimension == meshdimension == 2.
8786 * This method works only for linear cells.
8788 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
8790 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMesh() const
8792 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
8793 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
8794 MCAuto<MEDCouplingUMesh> skin(computeSkin());
8795 int oldNbOfNodes(skin->getNumberOfNodes());
8796 MCAuto<DataArrayInt> o2n(skin->zipCoordsTraducer());
8797 int nbOfNodesExpected(skin->getNumberOfNodes());
8798 MCAuto<DataArrayInt> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
8799 int nbCells(skin->getNumberOfCells());
8800 if(nbCells==nbOfNodesExpected)
8801 return buildUnionOf2DMeshLinear(skin,n2o);
8802 else if(2*nbCells==nbOfNodesExpected)
8803 return buildUnionOf2DMeshQuadratic(skin,n2o);
8805 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
8809 * This method makes the assumption spacedimension == meshdimension == 3.
8810 * This method works only for linear cells.
8812 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
8814 DataArrayInt *MEDCouplingUMesh::buildUnionOf3DMesh() const
8816 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8817 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
8818 MCAuto<MEDCouplingUMesh> m=computeSkin();
8819 const int *conn=m->getNodalConnectivity()->getConstPointer();
8820 const int *connI=m->getNodalConnectivityIndex()->getConstPointer();
8821 int nbOfCells=m->getNumberOfCells();
8822 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
8823 int *work=ret->getPointer(); *work++=INTERP_KERNEL::NORM_POLYHED;
8826 work=std::copy(conn+connI[0]+1,conn+connI[1],work);
8827 for(int i=1;i<nbOfCells;i++)
8830 work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
8836 * \brief Creates a graph of cell neighbors
8837 * \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
8838 * In the sky line array, graph arcs are stored in terms of (index,value) notation.
8840 * - index: 0 3 5 6 6
8841 * - value: 1 2 3 2 3 3
8842 * means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
8843 * Arcs are not doubled but reflexive (1,1) arcs are present for each cell
8845 MEDCouplingSkyLineArray *MEDCouplingUMesh::generateGraph() const
8847 checkConnectivityFullyDefined();
8849 int meshDim = this->getMeshDimension();
8850 MEDCoupling::DataArrayInt* indexr=MEDCoupling::DataArrayInt::New();
8851 MEDCoupling::DataArrayInt* revConn=MEDCoupling::DataArrayInt::New();
8852 this->getReverseNodalConnectivity(revConn,indexr);
8853 const int* indexr_ptr=indexr->getConstPointer();
8854 const int* revConn_ptr=revConn->getConstPointer();
8856 const MEDCoupling::DataArrayInt* index;
8857 const MEDCoupling::DataArrayInt* conn;
8858 conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
8859 index=this->getNodalConnectivityIndex();
8860 int nbCells=this->getNumberOfCells();
8861 const int* index_ptr=index->getConstPointer();
8862 const int* conn_ptr=conn->getConstPointer();
8864 //creating graph arcs (cell to cell relations)
8865 //arcs are stored in terms of (index,value) notation
8868 // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
8869 // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
8871 //warning here one node have less than or equal effective number of cell with it
8872 //but cell could have more than effective nodes
8873 //because other equals nodes in other domain (with other global inode)
8874 std::vector <int> cell2cell_index(nbCells+1,0);
8875 std::vector <int> cell2cell;
8876 cell2cell.reserve(3*nbCells);
8878 for (int icell=0; icell<nbCells;icell++)
8880 std::map<int,int > counter;
8881 for (int iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
8883 int inode=conn_ptr[iconn];
8884 for (int iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
8886 int icell2=revConn_ptr[iconnr];
8887 std::map<int,int>::iterator iter=counter.find(icell2);
8888 if (iter!=counter.end()) (iter->second)++;
8889 else counter.insert(std::make_pair(icell2,1));
8892 for (std::map<int,int>::const_iterator iter=counter.begin();
8893 iter!=counter.end(); iter++)
8894 if (iter->second >= meshDim)
8896 cell2cell_index[icell+1]++;
8897 cell2cell.push_back(iter->first);
8902 cell2cell_index[0]=0;
8903 for (int icell=0; icell<nbCells;icell++)
8904 cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
8906 //filling up index and value to create skylinearray structure
8907 MEDCouplingSkyLineArray* array=new MEDCouplingSkyLineArray(cell2cell_index,cell2cell);
8912 * This method put in zip format into parameter 'zipFrmt' in full interlace mode.
8913 * This format is often asked by INTERP_KERNEL algorithms to avoid many indirections into coordinates array.
8915 void MEDCouplingUMesh::FillInCompact3DMode(int spaceDim, int nbOfNodesInCell, const int *conn, const double *coo, double *zipFrmt)
8919 for(int i=0;i<nbOfNodesInCell;i++)
8920 w=std::copy(coo+3*conn[i],coo+3*conn[i]+3,w);
8921 else if(spaceDim==2)
8923 for(int i=0;i<nbOfNodesInCell;i++)
8925 w=std::copy(coo+2*conn[i],coo+2*conn[i]+2,w);
8930 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::FillInCompact3DMode : Invalid spaceDim specified : must be 2 or 3 !");
8933 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
8935 int nbOfCells=getNumberOfCells();
8937 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
8938 static const int PARAMEDMEM2VTKTYPETRADUCER[INTERP_KERNEL::NORM_MAXTYPE+1]={1,3,21,5,9,7,22,34,23,28,-1,-1,-1,-1,10,14,13,-1,12,-1,24,-1,16,27,-1,26,-1,29,-1,-1,25,42,36,4};
8939 ofs << " <" << getVTKDataSetType() << ">\n";
8940 ofs << " <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
8941 ofs << " <PointData>\n" << pointData << std::endl;
8942 ofs << " </PointData>\n";
8943 ofs << " <CellData>\n" << cellData << std::endl;
8944 ofs << " </CellData>\n";
8945 ofs << " <Points>\n";
8946 if(getSpaceDimension()==3)
8947 _coords->writeVTK(ofs,8,"Points",byteData);
8950 MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
8951 coo->writeVTK(ofs,8,"Points",byteData);
8953 ofs << " </Points>\n";
8954 ofs << " <Cells>\n";
8955 const int *cPtr=_nodal_connec->getConstPointer();
8956 const int *cIPtr=_nodal_connec_index->getConstPointer();
8957 MCAuto<DataArrayInt> faceoffsets=DataArrayInt::New(); faceoffsets->alloc(nbOfCells,1);
8958 MCAuto<DataArrayInt> types=DataArrayInt::New(); types->alloc(nbOfCells,1);
8959 MCAuto<DataArrayInt> offsets=DataArrayInt::New(); offsets->alloc(nbOfCells,1);
8960 MCAuto<DataArrayInt> connectivity=DataArrayInt::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
8961 int *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
8962 int szFaceOffsets=0,szConn=0;
8963 for(int i=0;i<nbOfCells;i++,w1++,w2++,w3++)
8966 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
8969 *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
8970 w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
8974 int deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
8975 *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
8976 std::set<int> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
8977 *w3=szConn+(int)c.size(); szConn+=(int)c.size();
8978 w4=std::copy(c.begin(),c.end(),w4);
8981 types->transformWithIndArr(PARAMEDMEM2VTKTYPETRADUCER,PARAMEDMEM2VTKTYPETRADUCER+INTERP_KERNEL::NORM_MAXTYPE+1);
8982 types->writeVTK(ofs,8,"UInt8","types",byteData);
8983 offsets->writeVTK(ofs,8,"Int32","offsets",byteData);
8984 if(szFaceOffsets!=0)
8985 {//presence of Polyhedra
8986 connectivity->reAlloc(szConn);
8987 faceoffsets->writeVTK(ofs,8,"Int32","faceoffsets",byteData);
8988 MCAuto<DataArrayInt> faces=DataArrayInt::New(); faces->alloc(szFaceOffsets,1);
8989 w1=faces->getPointer();
8990 for(int i=0;i<nbOfCells;i++)
8991 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
8993 int nbFaces=std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1)+1;
8995 const int *w6=cPtr+cIPtr[i]+1,*w5=0;
8996 for(int j=0;j<nbFaces;j++)
8998 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
8999 *w1++=(int)std::distance(w6,w5);
9000 w1=std::copy(w6,w5,w1);
9004 faces->writeVTK(ofs,8,"Int32","faces",byteData);
9006 connectivity->writeVTK(ofs,8,"Int32","connectivity",byteData);
9007 ofs << " </Cells>\n";
9008 ofs << " </Piece>\n";
9009 ofs << " </" << getVTKDataSetType() << ">\n";
9012 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
9014 stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
9016 { stream << " Not set !"; return ; }
9017 stream << " Mesh dimension : " << _mesh_dim << ".";
9021 { stream << " No coordinates set !"; return ; }
9022 if(!_coords->isAllocated())
9023 { stream << " Coordinates set but not allocated !"; return ; }
9024 stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
9025 stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
9026 if(!_nodal_connec_index)
9027 { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
9028 if(!_nodal_connec_index->isAllocated())
9029 { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
9030 int lgth=_nodal_connec_index->getNumberOfTuples();
9031 int cpt=_nodal_connec_index->getNumberOfComponents();
9032 if(cpt!=1 || lgth<1)
9034 stream << std::endl << "Number of cells : " << lgth-1 << ".";
9037 std::string MEDCouplingUMesh::getVTKDataSetType() const
9039 return std::string("UnstructuredGrid");
9042 std::string MEDCouplingUMesh::getVTKFileExtension() const
9044 return std::string("vtu");
9048 * Partitions the first given 2D mesh using the second given 2D mesh as a tool, and
9049 * returns a result mesh constituted by polygons.
9050 * Thus the final result contains all nodes from m1 plus new nodes. However it doesn't necessarily contains
9051 * all nodes from m2.
9052 * The meshes should be in 2D space. In
9053 * addition, returns two arrays mapping cells of the result mesh to cells of the input
9055 * \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
9056 * 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)
9057 * \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
9058 * 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)
9059 * \param [in] eps - precision used to detect coincident mesh entities.
9060 * \param [out] cellNb1 - a new instance of DataArrayInt holding for each result
9061 * cell an id of the cell of \a m1 it comes from. The caller is to delete
9062 * this array using decrRef() as it is no more needed.
9063 * \param [out] cellNb2 - a new instance of DataArrayInt holding for each result
9064 * cell an id of the cell of \a m2 it comes from. -1 value means that a
9065 * result cell comes from a cell (or part of cell) of \a m1 not overlapped by
9066 * any cell of \a m2. The caller is to delete this array using decrRef() as
9067 * it is no more needed.
9068 * \return MEDCouplingUMesh * - the result 2D mesh which is a new instance of
9069 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
9070 * is no more needed.
9071 * \throw If the coordinates array is not set in any of the meshes.
9072 * \throw If the nodal connectivity of cells is not defined in any of the meshes.
9073 * \throw If any of the meshes is not a 2D mesh in 2D space.
9075 * \sa conformize2D, mergeNodes
9077 MEDCouplingUMesh *MEDCouplingUMesh::Intersect2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2,
9078 double eps, DataArrayInt *&cellNb1, DataArrayInt *&cellNb2)
9081 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshes : input meshes must be not NULL !");
9082 m1->checkFullyDefined();
9083 m2->checkFullyDefined();
9084 if(m1->getMeshDimension()!=2 || m1->getSpaceDimension()!=2 || m2->getMeshDimension()!=2 || m2->getSpaceDimension()!=2)
9085 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshes works on umeshes m1 AND m2 with meshdim equal to 2 and spaceDim equal to 2 too!");
9087 // Step 1: compute all edge intersections (new nodes)
9088 std::vector< std::vector<int> > intersectEdge1, colinear2, subDiv2;
9089 MEDCouplingUMesh *m1Desc=0,*m2Desc=0; // descending connec. meshes
9090 DataArrayInt *desc1=0,*descIndx1=0,*revDesc1=0,*revDescIndx1=0,*desc2=0,*descIndx2=0,*revDesc2=0,*revDescIndx2=0;
9091 std::vector<double> addCoo,addCoordsQuadratic; // coordinates of newly created nodes
9092 IntersectDescending2DMeshes(m1,m2,eps,intersectEdge1,colinear2, subDiv2,
9093 m1Desc,desc1,descIndx1,revDesc1,revDescIndx1,
9094 addCoo, m2Desc,desc2,descIndx2,revDesc2,revDescIndx2);
9095 revDesc1->decrRef(); revDescIndx1->decrRef(); revDesc2->decrRef(); revDescIndx2->decrRef();
9096 MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(desc2),dd4(descIndx2);
9097 MCAuto<MEDCouplingUMesh> dd5(m1Desc),dd6(m2Desc);
9099 // Step 2: re-order newly created nodes according to the ordering found in m2
9100 std::vector< std::vector<int> > intersectEdge2;
9101 BuildIntersectEdges(m1Desc,m2Desc,addCoo,subDiv2,intersectEdge2);
9102 subDiv2.clear(); dd5=0; dd6=0;
9105 std::vector<int> cr,crI; //no DataArrayInt because interface with Geometric2D
9106 std::vector<int> cNb1,cNb2; //no DataArrayInt because interface with Geometric2D
9107 BuildIntersecting2DCellsFromEdges(eps,m1,desc1->getConstPointer(),descIndx1->getConstPointer(),intersectEdge1,colinear2,m2,desc2->getConstPointer(),descIndx2->getConstPointer(),intersectEdge2,addCoo,
9108 /* outputs -> */addCoordsQuadratic,cr,crI,cNb1,cNb2);
9110 // Step 4: Prepare final result:
9111 MCAuto<DataArrayDouble> addCooDa(DataArrayDouble::New());
9112 addCooDa->alloc((int)(addCoo.size())/2,2);
9113 std::copy(addCoo.begin(),addCoo.end(),addCooDa->getPointer());
9114 MCAuto<DataArrayDouble> addCoordsQuadraticDa(DataArrayDouble::New());
9115 addCoordsQuadraticDa->alloc((int)(addCoordsQuadratic.size())/2,2);
9116 std::copy(addCoordsQuadratic.begin(),addCoordsQuadratic.end(),addCoordsQuadraticDa->getPointer());
9117 std::vector<const DataArrayDouble *> coordss(4);
9118 coordss[0]=m1->getCoords(); coordss[1]=m2->getCoords(); coordss[2]=addCooDa; coordss[3]=addCoordsQuadraticDa;
9119 MCAuto<DataArrayDouble> coo(DataArrayDouble::Aggregate(coordss));
9120 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("Intersect2D",2));
9121 MCAuto<DataArrayInt> conn(DataArrayInt::New()); conn->alloc((int)cr.size(),1); std::copy(cr.begin(),cr.end(),conn->getPointer());
9122 MCAuto<DataArrayInt> connI(DataArrayInt::New()); connI->alloc((int)crI.size(),1); std::copy(crI.begin(),crI.end(),connI->getPointer());
9123 MCAuto<DataArrayInt> c1(DataArrayInt::New()); c1->alloc((int)cNb1.size(),1); std::copy(cNb1.begin(),cNb1.end(),c1->getPointer());
9124 MCAuto<DataArrayInt> c2(DataArrayInt::New()); c2->alloc((int)cNb2.size(),1); std::copy(cNb2.begin(),cNb2.end(),c2->getPointer());
9125 ret->setConnectivity(conn,connI,true);
9126 ret->setCoords(coo);
9127 cellNb1=c1.retn(); cellNb2=c2.retn();
9133 bool IsColinearOfACellOf(const std::vector< std::vector<int> >& intersectEdge1, const std::vector<int>& candidates, int start, int stop, int& retVal)
9135 if(candidates.empty())
9137 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
9139 const std::vector<int>& pool(intersectEdge1[*it]);
9140 int tmp[2]; tmp[0]=start; tmp[1]=stop;
9141 if(std::search(pool.begin(),pool.end(),tmp,tmp+2)!=pool.end())
9146 tmp[0]=stop; tmp[1]=start;
9147 if(std::search(pool.begin(),pool.end(),tmp,tmp+2)!=pool.end())
9156 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,
9157 MCAuto<DataArrayInt>& idsInRetColinear, MCAuto<DataArrayInt>& idsInMesh1DForIdsInRetColinear)
9159 idsInRetColinear=DataArrayInt::New(); idsInRetColinear->alloc(0,1);
9160 idsInMesh1DForIdsInRetColinear=DataArrayInt::New(); idsInMesh1DForIdsInRetColinear->alloc(0,1);
9161 int nCells(mesh1D->getNumberOfCells());
9162 if(nCells!=(int)intersectEdge2.size())
9163 throw INTERP_KERNEL::Exception("BuildMesh1DCutFrom : internal error # 1 !");
9164 const DataArrayDouble *coo2(mesh1D->getCoords());
9165 const int *c(mesh1D->getNodalConnectivity()->begin()),*ci(mesh1D->getNodalConnectivityIndex()->begin());
9166 const double *coo2Ptr(coo2->begin());
9167 int offset1(coords1->getNumberOfTuples());
9168 int offset2(offset1+coo2->getNumberOfTuples());
9169 int offset3(offset2+addCoo.size()/2);
9170 std::vector<double> addCooQuad;
9171 MCAuto<DataArrayInt> cOut(DataArrayInt::New()),ciOut(DataArrayInt::New()); cOut->alloc(0,1); ciOut->alloc(1,1); ciOut->setIJ(0,0,0);
9172 int tmp[4],cicnt(0),kk(0);
9173 for(int i=0;i<nCells;i++)
9175 std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
9176 INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coo2Ptr,m));
9177 const std::vector<int>& subEdges(intersectEdge2[i]);
9178 int nbSubEdge(subEdges.size()/2);
9179 for(int j=0;j<nbSubEdge;j++,kk++)
9181 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));
9182 MCAuto<INTERP_KERNEL::Edge> e2(e->buildEdgeLyingOnMe(n1,n2));
9183 INTERP_KERNEL::Edge *e2Ptr(e2);
9184 std::map<int,int>::const_iterator itm;
9185 if(dynamic_cast<INTERP_KERNEL::EdgeArcCircle *>(e2Ptr))
9187 tmp[0]=INTERP_KERNEL::NORM_SEG3;
9188 itm=mergedNodes.find(subEdges[2*j]);
9189 tmp[1]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j];
9190 itm=mergedNodes.find(subEdges[2*j+1]);
9191 tmp[2]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j+1];
9192 tmp[3]=offset3+(int)addCooQuad.size()/2;
9194 e2->getBarycenter(tmp2); addCooQuad.insert(addCooQuad.end(),tmp2,tmp2+2);
9196 cOut->insertAtTheEnd(tmp,tmp+4);
9197 ciOut->pushBackSilent(cicnt);
9201 tmp[0]=INTERP_KERNEL::NORM_SEG2;
9202 itm=mergedNodes.find(subEdges[2*j]);
9203 tmp[1]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j];
9204 itm=mergedNodes.find(subEdges[2*j+1]);
9205 tmp[2]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j+1];
9207 cOut->insertAtTheEnd(tmp,tmp+3);
9208 ciOut->pushBackSilent(cicnt);
9211 if(IsColinearOfACellOf(intersectEdge1,colinear2[i],tmp[1],tmp[2],tmp00))
9213 idsInRetColinear->pushBackSilent(kk);
9214 idsInMesh1DForIdsInRetColinear->pushBackSilent(tmp00);
9219 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(mesh1D->getName(),1));
9220 ret->setConnectivity(cOut,ciOut,true);
9221 MCAuto<DataArrayDouble> arr3(DataArrayDouble::New());
9222 arr3->useArray(&addCoo[0],false,C_DEALLOC,(int)addCoo.size()/2,2);
9223 MCAuto<DataArrayDouble> arr4(DataArrayDouble::New()); arr4->useArray(&addCooQuad[0],false,C_DEALLOC,(int)addCooQuad.size()/2,2);
9224 std::vector<const DataArrayDouble *> coordss(4);
9225 coordss[0]=coords1; coordss[1]=mesh1D->getCoords(); coordss[2]=arr3; coordss[3]=arr4;
9226 MCAuto<DataArrayDouble> arr(DataArrayDouble::Aggregate(coordss));
9227 ret->setCoords(arr);
9231 MEDCouplingUMesh *BuildRefined2DCellLinear(const DataArrayDouble *coords, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9233 std::vector<int> allEdges;
9234 for(const int *it2(descBg);it2!=descEnd;it2++)
9236 const std::vector<int>& edge1(intersectEdge1[std::abs(*it2)-1]);
9238 allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9240 allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9242 std::size_t nb(allEdges.size());
9244 throw INTERP_KERNEL::Exception("BuildRefined2DCellLinear : internal error 1 !");
9245 std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9246 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
9247 ret->setCoords(coords);
9248 ret->allocateCells(1);
9249 std::vector<int> connOut(nbOfEdgesOf2DCellSplit);
9250 for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9251 connOut[kk]=allEdges[2*kk];
9252 ret->insertNextCell(INTERP_KERNEL::NORM_POLYGON,connOut.size(),&connOut[0]);
9256 MEDCouplingUMesh *BuildRefined2DCellQuadratic(const DataArrayDouble *coords, const MEDCouplingUMesh *mesh2D, int cellIdInMesh2D, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9258 const int *c(mesh2D->getNodalConnectivity()->begin()),*ci(mesh2D->getNodalConnectivityIndex()->begin());
9259 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[cellIdInMesh2D]]));
9261 unsigned sz(cm.getNumberOfSons2(c+ci[cellIdInMesh2D]+1,ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]-1));
9262 if(sz!=std::distance(descBg,descEnd))
9263 throw INTERP_KERNEL::Exception("BuildRefined2DCellQuadratic : internal error 1 !");
9264 INTERP_KERNEL::AutoPtr<int> tmpPtr(new int[ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]]);
9265 std::vector<int> allEdges,centers;
9266 const double *coordsPtr(coords->begin());
9267 MCAuto<DataArrayDouble> addCoo(DataArrayDouble::New()); addCoo->alloc(0,1);
9268 int offset(coords->getNumberOfTuples());
9269 for(const int *it2(descBg);it2!=descEnd;it2++,ii++)
9271 INTERP_KERNEL::NormalizedCellType typeOfSon;
9272 cm.fillSonCellNodalConnectivity2(ii,c+ci[cellIdInMesh2D]+1,ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]-1,tmpPtr,typeOfSon);
9273 const std::vector<int>& edge1(intersectEdge1[std::abs(*it2)-1]);
9275 allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9277 allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9279 centers.push_back(tmpPtr[2]);//special case where no subsplit of edge -> reuse the original center.
9281 {//the current edge has been subsplit -> create corresponding centers.
9282 std::size_t nbOfCentersToAppend(edge1.size()/2);
9283 std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9284 MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpPtr,coordsPtr,m));
9285 std::vector<int>::const_iterator it3(allEdges.end()-edge1.size());
9286 for(std::size_t k=0;k<nbOfCentersToAppend;k++)
9289 const double *aa(coordsPtr+2*(*it3++));
9290 const double *bb(coordsPtr+2*(*it3++));
9291 ee->getMiddleOfPoints(aa,bb,tmpp);
9292 addCoo->insertAtTheEnd(tmpp,tmpp+2);
9293 centers.push_back(offset+k);
9297 std::size_t nb(allEdges.size());
9299 throw INTERP_KERNEL::Exception("BuildRefined2DCellQuadratic : internal error 2 !");
9300 std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9301 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
9303 ret->setCoords(coords);
9306 addCoo->rearrange(2);
9307 addCoo=DataArrayDouble::Aggregate(coords,addCoo);
9308 ret->setCoords(addCoo);
9310 ret->allocateCells(1);
9311 std::vector<int> connOut(nbOfEdgesOf2DCellSplit);
9312 for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9313 connOut[kk]=allEdges[2*kk];
9314 connOut.insert(connOut.end(),centers.begin(),centers.end());
9315 ret->insertNextCell(INTERP_KERNEL::NORM_QPOLYG,connOut.size(),&connOut[0]);
9320 * This method creates a refinement of a cell in \a mesh2D. Those cell is defined by descending connectivity and the sorted subdivided nodal connectivity
9323 * \param [in] mesh2D - The origin 2D mesh. \b Warning \b coords are not those of \a mesh2D. But mesh2D->getCoords()==coords[:mesh2D->getNumberOfNodes()]
9325 MEDCouplingUMesh *BuildRefined2DCell(const DataArrayDouble *coords, const MEDCouplingUMesh *mesh2D, int cellIdInMesh2D, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9327 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(mesh2D->getTypeOfCell(cellIdInMesh2D)));
9328 if(!cm.isQuadratic())
9329 return BuildRefined2DCellLinear(coords,descBg,descEnd,intersectEdge1);
9331 return BuildRefined2DCellQuadratic(coords,mesh2D,cellIdInMesh2D,descBg,descEnd,intersectEdge1);
9334 void AddCellInMesh2D(MEDCouplingUMesh *mesh2D, const std::vector<int>& conn, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edges)
9337 for(std::vector< MCAuto<INTERP_KERNEL::Edge> >::const_iterator it=edges.begin();it!=edges.end();it++)
9339 const INTERP_KERNEL::Edge *ee(*it);
9340 if(dynamic_cast<const INTERP_KERNEL::EdgeArcCircle *>(ee))
9344 mesh2D->insertNextCell(INTERP_KERNEL::NORM_POLYGON,conn.size(),&conn[0]);
9347 const double *coo(mesh2D->getCoords()->begin());
9348 std::size_t sz(conn.size());
9349 std::vector<double> addCoo;
9350 std::vector<int> conn2(conn);
9351 int offset(mesh2D->getNumberOfNodes());
9352 for(std::size_t i=0;i<sz;i++)
9355 edges[(i+1)%sz]->getMiddleOfPoints(coo+2*conn[i],coo+2*conn[(i+1)%sz],tmp);// tony a chier i+1 -> i
9356 addCoo.insert(addCoo.end(),tmp,tmp+2);
9357 conn2.push_back(offset+(int)i);
9359 mesh2D->getCoords()->rearrange(1);
9360 mesh2D->getCoords()->pushBackValsSilent(&addCoo[0],&addCoo[0]+addCoo.size());
9361 mesh2D->getCoords()->rearrange(2);
9362 mesh2D->insertNextCell(INTERP_KERNEL::NORM_QPOLYG,conn2.size(),&conn2[0]);
9367 * \b WARNING edges in out1 coming from \a splitMesh1D are \b NOT oriented because only used for equation of curve.
9369 * This method cuts in 2 parts the input 2D cell given using boundaries description (\a edge1Bis and \a edge1BisPtr) using
9370 * a set of edges defined in \a splitMesh1D.
9372 void BuildMesh2DCutInternal2(const MEDCouplingUMesh *splitMesh1D, const std::vector<int>& edge1Bis, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edge1BisPtr,
9373 std::vector< std::vector<int> >& out0, std::vector< std::vector< MCAuto<INTERP_KERNEL::Edge> > >& out1)
9375 std::size_t nb(edge1Bis.size()/2);
9376 std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9377 int iEnd(splitMesh1D->getNumberOfCells());
9379 throw INTERP_KERNEL::Exception("BuildMesh2DCutInternal2 : internal error ! input 1D mesh must have at least one cell !");
9381 const int *cSplitPtr(splitMesh1D->getNodalConnectivity()->begin()),*ciSplitPtr(splitMesh1D->getNodalConnectivityIndex()->begin());
9382 for(ii=0;ii<nb && edge1Bis[2*ii]!=cSplitPtr[ciSplitPtr[0]+1];ii++);
9383 for(jj=ii;jj<nb && edge1Bis[2*jj+1]!=cSplitPtr[ciSplitPtr[iEnd-1]+2];jj++);
9386 {//the edges splitMesh1D[iStart:iEnd] does not fully cut the current 2D cell -> single output cell
9387 out0.resize(1); out1.resize(1);
9388 std::vector<int>& connOut(out0[0]);
9389 connOut.resize(nbOfEdgesOf2DCellSplit);
9390 std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr(out1[0]);
9391 edgesPtr.resize(nbOfEdgesOf2DCellSplit);
9392 for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9394 connOut[kk]=edge1Bis[2*kk];
9395 edgesPtr[kk]=edge1BisPtr[2*kk];
9400 // [i,iEnd[ contains the
9401 out0.resize(2); out1.resize(2);
9402 std::vector<int>& connOutLeft(out0[0]);
9403 std::vector<int>& connOutRight(out0[1]);//connOutLeft should end with edge1Bis[2*ii] and connOutRight should end with edge1Bis[2*jj+1]
9404 std::vector< MCAuto<INTERP_KERNEL::Edge> >& eleft(out1[0]);
9405 std::vector< MCAuto<INTERP_KERNEL::Edge> >& eright(out1[1]);
9406 for(std::size_t k=ii;k<jj+1;k++)
9407 { connOutLeft.push_back(edge1Bis[2*k+1]); eleft.push_back(edge1BisPtr[2*k+1]); }
9408 std::vector< MCAuto<INTERP_KERNEL::Edge> > ees(iEnd);
9409 for(int ik=0;ik<iEnd;ik++)
9411 std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9412 MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)cSplitPtr[ciSplitPtr[ik]],cSplitPtr+ciSplitPtr[ik]+1,splitMesh1D->getCoords()->begin(),m));
9415 for(int ik=iEnd-1;ik>=0;ik--)
9416 connOutLeft.push_back(cSplitPtr[ciSplitPtr[ik]+1]);
9417 for(std::size_t k=jj+1;k<nbOfEdgesOf2DCellSplit+ii;k++)
9418 { connOutRight.push_back(edge1Bis[2*k+1]); eright.push_back(edge1BisPtr[2*k+1]); }
9419 eleft.insert(eleft.end(),ees.rbegin(),ees.rend());
9420 for(int ik=0;ik<iEnd;ik++)
9421 connOutRight.push_back(cSplitPtr[ciSplitPtr[ik]+2]);
9422 eright.insert(eright.end(),ees.begin(),ees.end());
9434 CellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr);
9436 std::vector<int> _edges;
9437 std::vector< MCAuto<INTERP_KERNEL::Edge> > _edges_ptr;
9440 CellInfo::CellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr)
9442 std::size_t nbe(edges.size());
9443 std::vector<int> edges2(2*nbe); std::vector< MCAuto<INTERP_KERNEL::Edge> > edgesPtr2(2*nbe);
9444 for(std::size_t i=0;i<nbe;i++)
9446 edges2[2*i]=edges[i]; edges2[2*i+1]=edges[(i+1)%nbe];
9447 edgesPtr2[2*i]=edgesPtr[(i+1)%nbe]; edgesPtr2[2*i+1]=edgesPtr[(i+1)%nbe];//tony a chier
9449 _edges.resize(4*nbe); _edges_ptr.resize(4*nbe);
9450 std::copy(edges2.begin(),edges2.end(),_edges.begin()); std::copy(edges2.begin(),edges2.end(),_edges.begin()+2*nbe);
9451 std::copy(edgesPtr2.begin(),edgesPtr2.end(),_edges_ptr.begin()); std::copy(edgesPtr2.begin(),edgesPtr2.end(),_edges_ptr.begin()+2*nbe);
9457 EdgeInfo(int istart, int iend, const MCAuto<MEDCouplingUMesh>& mesh):_istart(istart),_iend(iend),_mesh(mesh),_left(-7),_right(-7) { }
9458 EdgeInfo(int istart, int iend, int pos, const MCAuto<INTERP_KERNEL::Edge>& edge):_istart(istart),_iend(iend),_edge(edge),_left(pos),_right(pos+1) { }
9459 bool isInMyRange(int pos) const { return pos>=_istart && pos<_iend; }
9460 void somethingHappendAt(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight);
9461 void feedEdgeInfoAt(double eps, const MEDCouplingUMesh *mesh2D, int offset, int neighbors[2]) const;
9465 MCAuto<MEDCouplingUMesh> _mesh;
9466 MCAuto<INTERP_KERNEL::Edge> _edge;
9471 void EdgeInfo::somethingHappendAt(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight)
9473 const MEDCouplingUMesh *mesh(_mesh);
9479 { _left++; _right++; return ; }
9482 bool isLeft(std::find(newLeft.begin(),newLeft.end(),_edge)!=newLeft.end()),isRight(std::find(newRight.begin(),newRight.end(),_edge)!=newRight.end());
9483 if((isLeft && isRight) || (!isLeft && !isRight))
9484 throw INTERP_KERNEL::Exception("EdgeInfo::somethingHappendAt : internal error # 1 !");
9495 bool isLeft(std::find(newLeft.begin(),newLeft.end(),_edge)!=newLeft.end()),isRight(std::find(newRight.begin(),newRight.end(),_edge)!=newRight.end());
9496 if((isLeft && isRight) || (!isLeft && !isRight))
9497 throw INTERP_KERNEL::Exception("EdgeInfo::somethingHappendAt : internal error # 2 !");
9512 void EdgeInfo::feedEdgeInfoAt(double eps, const MEDCouplingUMesh *mesh2D, int offset, int neighbors[2]) const
9514 const MEDCouplingUMesh *mesh(_mesh);
9517 neighbors[0]=offset+_left; neighbors[1]=offset+_right;
9520 {// not fully splitting cell case
9521 if(mesh2D->getNumberOfCells()==1)
9522 {//little optimization. 1 cell no need to find in which cell mesh is !
9523 neighbors[0]=offset; neighbors[1]=offset;
9528 MCAuto<DataArrayDouble> barys(mesh->computeCellCenterOfMass());
9529 int cellId(mesh2D->getCellContainingPoint(barys->begin(),eps));
9531 throw INTERP_KERNEL::Exception("EdgeInfo::feedEdgeInfoAt : internal error !");
9532 neighbors[0]=offset+cellId; neighbors[1]=offset+cellId;
9537 class VectorOfCellInfo
9540 VectorOfCellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr);
9541 std::size_t size() const { return _pool.size(); }
9542 int getPositionOf(double eps, const MEDCouplingUMesh *mesh) const;
9543 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);
9544 const std::vector<int>& getConnOf(int pos) const { return get(pos)._edges; }
9545 const std::vector< MCAuto<INTERP_KERNEL::Edge> >& getEdgePtrOf(int pos) const { return get(pos)._edges_ptr; }
9546 MCAuto<MEDCouplingUMesh> getZeMesh() const { return _ze_mesh; }
9547 void feedEdgeInfoAt(double eps, int pos, int offset, int neighbors[2]) const;
9549 int getZePosOfEdgeGivenItsGlobalId(int pos) const;
9550 void updateEdgeInfo(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight);
9551 const CellInfo& get(int pos) const;
9552 CellInfo& get(int pos);
9554 std::vector<CellInfo> _pool;
9555 MCAuto<MEDCouplingUMesh> _ze_mesh;
9556 std::vector<EdgeInfo> _edge_info;
9559 VectorOfCellInfo::VectorOfCellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr):_pool(1)
9561 _pool[0]._edges=edges;
9562 _pool[0]._edges_ptr=edgesPtr;
9565 int VectorOfCellInfo::getPositionOf(double eps, const MEDCouplingUMesh *mesh) const
9568 throw INTERP_KERNEL::Exception("VectorOfCellSplitter::getPositionOf : empty !");
9571 const MEDCouplingUMesh *zeMesh(_ze_mesh);
9573 throw INTERP_KERNEL::Exception("VectorOfCellSplitter::getPositionOf : null aggregated mesh !");
9574 MCAuto<DataArrayDouble> barys(mesh->computeCellCenterOfMass());
9575 return zeMesh->getCellContainingPoint(barys->begin(),eps);
9578 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)
9580 get(pos);//to check pos
9581 bool isFast(pos==0 && _pool.size()==1);
9582 std::size_t sz(edges.size());
9583 // dealing with edges
9585 _edge_info.push_back(EdgeInfo(istart,iend,mesh1DInCase));
9587 _edge_info.push_back(EdgeInfo(istart,iend,pos,edgePtrs[0].back()));
9589 std::vector<CellInfo> pool(_pool.size()-1+sz);
9590 for(int i=0;i<pos;i++)
9592 for(std::size_t j=0;j<sz;j++)
9593 pool[pos+j]=CellInfo(edges[j],edgePtrs[j]);
9594 for(int i=pos+1;i<(int)_pool.size();i++)
9595 pool[i+sz-1]=_pool[i];
9599 updateEdgeInfo(pos,edgePtrs[0],edgePtrs[1]);
9607 std::vector< MCAuto<MEDCouplingUMesh> > ms;
9610 MCAuto<MEDCouplingUMesh> elt(static_cast<MEDCouplingUMesh *>(_ze_mesh->buildPartOfMySelfSlice(0,pos,true)));
9614 if(pos<_ze_mesh->getNumberOfCells()-1)
9616 MCAuto<MEDCouplingUMesh> elt(static_cast<MEDCouplingUMesh *>(_ze_mesh->buildPartOfMySelfSlice(pos+1,_ze_mesh->getNumberOfCells(),true)));
9619 std::vector< const MEDCouplingUMesh *> ms2(ms.size());
9620 for(std::size_t j=0;j<ms2.size();j++)
9622 _ze_mesh=MEDCouplingUMesh::MergeUMeshesOnSameCoords(ms2);
9625 void VectorOfCellInfo::feedEdgeInfoAt(double eps, int pos, int offset, int neighbors[2]) const
9627 _edge_info[getZePosOfEdgeGivenItsGlobalId(pos)].feedEdgeInfoAt(eps,_ze_mesh,offset,neighbors);
9630 int VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId(int pos) const
9633 throw INTERP_KERNEL::Exception("VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId : invalid id ! Must be >=0 !");
9635 for(std::vector<EdgeInfo>::const_iterator it=_edge_info.begin();it!=_edge_info.end();it++,ret++)
9637 if((*it).isInMyRange(pos))
9640 throw INTERP_KERNEL::Exception("VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId : invalid id !");
9643 void VectorOfCellInfo::updateEdgeInfo(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight)
9645 get(pos);//to check;
9646 if(_edge_info.empty())
9648 std::size_t sz(_edge_info.size()-1);
9649 for(std::size_t i=0;i<sz;i++)
9650 _edge_info[i].somethingHappendAt(pos,newLeft,newRight);
9653 const CellInfo& VectorOfCellInfo::get(int pos) const
9655 if(pos<0 || pos>=(int)_pool.size())
9656 throw INTERP_KERNEL::Exception("VectorOfCellSplitter::get const : invalid pos !");
9660 CellInfo& VectorOfCellInfo::get(int pos)
9662 if(pos<0 || pos>=(int)_pool.size())
9663 throw INTERP_KERNEL::Exception("VectorOfCellSplitter::get : invalid pos !");
9669 * - a \b closed set of edges ( \a allEdges and \a allEdgesPtr ) that defines the split descending 2D cell.
9670 * - \a splitMesh1D a split 2D curve mesh contained into 2D cell defined above.
9672 * This method returns the 2D mesh and feeds \a idsLeftRight using offset.
9674 * Algorithm : \a splitMesh1D is cut into contiguous parts. Each contiguous parts will build incrementally the output 2D cells.
9676 * \param [in] allEdges a list of pairs (beginNode, endNode). Linked with \a allEdgesPtr to get the equation of edge.
9678 MEDCouplingUMesh *BuildMesh2DCutInternal(double eps, const MEDCouplingUMesh *splitMesh1D, const std::vector<int>& allEdges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& allEdgesPtr, int offset,
9679 MCAuto<DataArrayInt>& idsLeftRight)
9681 int nbCellsInSplitMesh1D(splitMesh1D->getNumberOfCells());
9682 if(nbCellsInSplitMesh1D==0)
9683 throw INTERP_KERNEL::Exception("BuildMesh2DCutInternal : internal error ! input 1D mesh must have at least one cell !");
9684 const int *cSplitPtr(splitMesh1D->getNodalConnectivity()->begin()),*ciSplitPtr(splitMesh1D->getNodalConnectivityIndex()->begin());
9685 std::size_t nb(allEdges.size()),jj;
9687 throw INTERP_KERNEL::Exception("BuildMesh2DCutFrom : internal error 2 !");
9688 std::vector<int> edge1Bis(nb*2);
9689 std::vector< MCAuto<INTERP_KERNEL::Edge> > edge1BisPtr(nb*2);
9690 std::copy(allEdges.begin(),allEdges.end(),edge1Bis.begin());
9691 std::copy(allEdges.begin(),allEdges.end(),edge1Bis.begin()+nb);
9692 std::copy(allEdgesPtr.begin(),allEdgesPtr.end(),edge1BisPtr.begin());
9693 std::copy(allEdgesPtr.begin(),allEdgesPtr.end(),edge1BisPtr.begin()+nb);
9695 idsLeftRight=DataArrayInt::New(); idsLeftRight->alloc(nbCellsInSplitMesh1D*2); idsLeftRight->fillWithValue(-2); idsLeftRight->rearrange(2);
9696 int *idsLeftRightPtr(idsLeftRight->getPointer());
9697 VectorOfCellInfo pool(edge1Bis,edge1BisPtr);
9698 for(int iStart=0;iStart<nbCellsInSplitMesh1D;)
9699 {// split [0:nbCellsInSplitMesh1D) in contiguous parts [iStart:iEnd)
9701 for(;iEnd<nbCellsInSplitMesh1D;)
9703 for(jj=0;jj<nb && edge1Bis[2*jj+1]!=cSplitPtr[ciSplitPtr[iEnd]+2];jj++);
9709 if(iEnd<nbCellsInSplitMesh1D)
9712 MCAuto<MEDCouplingUMesh> partOfSplitMesh1D(static_cast<MEDCouplingUMesh *>(splitMesh1D->buildPartOfMySelfSlice(iStart,iEnd,1,true)));
9713 int pos(pool.getPositionOf(eps,partOfSplitMesh1D));
9715 MCAuto<MEDCouplingUMesh>retTmp(MEDCouplingUMesh::New("",2));
9716 retTmp->setCoords(splitMesh1D->getCoords());
9717 retTmp->allocateCells();
9719 std::vector< std::vector<int> > out0;
9720 std::vector< std::vector< MCAuto<INTERP_KERNEL::Edge> > > out1;
9722 BuildMesh2DCutInternal2(partOfSplitMesh1D,pool.getConnOf(pos),pool.getEdgePtrOf(pos),out0,out1);
9723 for(std::size_t cnt=0;cnt<out0.size();cnt++)
9724 AddCellInMesh2D(retTmp,out0[cnt],out1[cnt]);
9725 pool.setMeshAt(pos,retTmp,iStart,iEnd,partOfSplitMesh1D,out0,out1);
9729 for(int mm=0;mm<nbCellsInSplitMesh1D;mm++)
9730 pool.feedEdgeInfoAt(eps,mm,offset,idsLeftRightPtr+2*mm);
9731 return pool.getZeMesh().retn();
9734 MEDCouplingUMesh *BuildMesh2DCutFrom(double eps, int cellIdInMesh2D, const MEDCouplingUMesh *mesh2DDesc, const MEDCouplingUMesh *splitMesh1D,
9735 const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1, int offset,
9736 MCAuto<DataArrayInt>& idsLeftRight)
9738 const int *cdescPtr(mesh2DDesc->getNodalConnectivity()->begin()),*cidescPtr(mesh2DDesc->getNodalConnectivityIndex()->begin());
9740 std::vector<int> allEdges;
9741 std::vector< MCAuto<INTERP_KERNEL::Edge> > allEdgesPtr; // for each sub edge in splitMesh2D the uncut Edge object of the original mesh2D
9742 for(const int *it(descBg);it!=descEnd;it++) // for all edges in the descending connectivity of the 2D mesh in relative Fortran mode
9744 int edgeId(std::abs(*it)-1);
9745 std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9746 MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)cdescPtr[cidescPtr[edgeId]],cdescPtr+cidescPtr[edgeId]+1,mesh2DDesc->getCoords()->begin(),m));
9747 const std::vector<int>& edge1(intersectEdge1[edgeId]);
9749 allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9751 allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9752 std::size_t sz(edge1.size());
9753 for(std::size_t cnt=0;cnt<sz;cnt++)
9754 allEdgesPtr.push_back(ee);
9757 return BuildMesh2DCutInternal(eps,splitMesh1D,allEdges,allEdgesPtr,offset,idsLeftRight);
9760 bool AreEdgeEqual(const double *coo2D, const INTERP_KERNEL::CellModel& typ1, const int *conn1, const INTERP_KERNEL::CellModel& typ2, const int *conn2, double eps)
9762 if(!typ1.isQuadratic() && !typ2.isQuadratic())
9763 {//easy case comparison not
9764 return conn1[0]==conn2[0] && conn1[1]==conn2[1];
9766 else if(typ1.isQuadratic() && typ2.isQuadratic())
9768 bool status0(conn1[0]==conn2[0] && conn1[1]==conn2[1]);
9771 if(conn1[2]==conn2[2])
9773 const double *a(coo2D+2*conn1[2]),*b(coo2D+2*conn2[2]);
9774 double dist(sqrt((a[0]-b[0])*(a[0]-b[0])+(a[1]-b[1])*(a[1]-b[1])));
9778 {//only one is quadratic
9779 bool status0(conn1[0]==conn2[0] && conn1[1]==conn2[1]);
9782 const double *a(0),*bb(0),*be(0);
9783 if(typ1.isQuadratic())
9785 a=coo2D+2*conn1[2]; bb=coo2D+2*conn2[0]; be=coo2D+2*conn2[1];
9789 a=coo2D+2*conn2[2]; bb=coo2D+2*conn1[0]; be=coo2D+2*conn1[1];
9791 double b[2]; b[0]=(be[0]+bb[0])/2.; b[1]=(be[1]+bb[1])/2.;
9792 double dist(sqrt((a[0]-b[0])*(a[0]-b[0])+(a[1]-b[1])*(a[1]-b[1])));
9798 * This method returns among the cellIds [ \a candidatesIn2DBg , \a candidatesIn2DEnd ) in \a mesh2DSplit those exactly sharing \a cellIdInMesh1DSplitRelative in \a mesh1DSplit.
9799 * \a mesh2DSplit and \a mesh1DSplit are expected to share the coordinates array.
9801 * \param [in] cellIdInMesh1DSplitRelative is in Fortran mode using sign to specify direction.
9803 int FindRightCandidateAmong(const MEDCouplingUMesh *mesh2DSplit, const int *candidatesIn2DBg, const int *candidatesIn2DEnd, const MEDCouplingUMesh *mesh1DSplit, int cellIdInMesh1DSplitRelative, double eps)
9805 if(candidatesIn2DEnd==candidatesIn2DBg)
9806 throw INTERP_KERNEL::Exception("FindRightCandidateAmong : internal error 1 !");
9807 const double *coo(mesh2DSplit->getCoords()->begin());
9808 if(std::distance(candidatesIn2DBg,candidatesIn2DEnd)==1)
9809 return *candidatesIn2DBg;
9810 int edgeId(std::abs(cellIdInMesh1DSplitRelative)-1);
9811 MCAuto<MEDCouplingUMesh> cur1D(static_cast<MEDCouplingUMesh *>(mesh1DSplit->buildPartOfMySelf(&edgeId,&edgeId+1,true)));
9812 if(cellIdInMesh1DSplitRelative<0)
9813 cur1D->changeOrientationOfCells();
9814 const int *c1D(cur1D->getNodalConnectivity()->begin());
9815 const INTERP_KERNEL::CellModel& ref1DType(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c1D[0]));
9816 for(const int *it=candidatesIn2DBg;it!=candidatesIn2DEnd;it++)
9818 MCAuto<MEDCouplingUMesh> cur2D(static_cast<MEDCouplingUMesh *>(mesh2DSplit->buildPartOfMySelf(it,it+1,true)));
9819 const int *c(cur2D->getNodalConnectivity()->begin()),*ci(cur2D->getNodalConnectivityIndex()->begin());
9820 const INTERP_KERNEL::CellModel &cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[0]]));
9821 unsigned sz(cm.getNumberOfSons2(c+ci[0]+1,ci[1]-ci[0]-1));
9822 INTERP_KERNEL::AutoPtr<int> tmpPtr(new int[ci[1]-ci[0]]);
9823 for(unsigned it2=0;it2<sz;it2++)
9825 INTERP_KERNEL::NormalizedCellType typeOfSon;
9826 cm.fillSonCellNodalConnectivity2(it2,c+ci[0]+1,ci[1]-ci[0]-1,tmpPtr,typeOfSon);
9827 const INTERP_KERNEL::CellModel &curCM(INTERP_KERNEL::CellModel::GetCellModel(typeOfSon));
9828 if(AreEdgeEqual(coo,ref1DType,c1D+1,curCM,tmpPtr,eps))
9832 throw INTERP_KERNEL::Exception("FindRightCandidateAmong : internal error 2 ! Unable to find the edge among split cell !");
9838 * Partitions the first given 2D mesh using the second given 1D mesh as a tool.
9839 * 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
9840 * and finaly, in case of quadratic polygon the centers of edges new nodes.
9841 * The meshes should be in 2D space. In addition, returns two arrays mapping cells of the resulting mesh to cells of the input.
9843 * \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
9844 * 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)
9845 * \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
9846 * you can invoke orderConsecutiveCells1D on \a mesh1D.
9847 * \param [in] eps - precision used to perform intersections and localization operations.
9848 * \param [out] splitMesh2D - the result of the split of \a mesh2D mesh.
9849 * \param [out] splitMesh1D - the result of the split of \a mesh1D mesh.
9850 * \param [out] cellIdInMesh2D - the array that gives for each cell id \a i in \a splitMesh2D the id in \a mesh2D it comes from.
9851 * 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.
9852 * \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
9853 * and the cell in \a splitMesh2D on the right for the 2nt component. -1 means no cell.
9854 * 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.
9856 * \sa Intersect2DMeshes, orderConsecutiveCells1D, conformize2D, mergeNodes
9858 void MEDCouplingUMesh::Intersect2DMeshWith1DLine(const MEDCouplingUMesh *mesh2D, const MEDCouplingUMesh *mesh1D, double eps, MEDCouplingUMesh *&splitMesh2D, MEDCouplingUMesh *&splitMesh1D, DataArrayInt *&cellIdInMesh2D, DataArrayInt *&cellIdInMesh1D)
9860 if(!mesh2D || !mesh1D)
9861 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshWith1DLine : input meshes must be not NULL !");
9862 mesh2D->checkFullyDefined();
9863 mesh1D->checkFullyDefined();
9864 const std::vector<std::string>& compNames(mesh2D->getCoords()->getInfoOnComponents());
9865 if(mesh2D->getMeshDimension()!=2 || mesh2D->getSpaceDimension()!=2 || mesh1D->getMeshDimension()!=1 || mesh1D->getSpaceDimension()!=2)
9866 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshWith1DLine works with mesh2D with spacedim=meshdim=2 and mesh1D with meshdim=1 spaceDim=2 !");
9867 // Step 1: compute all edge intersections (new nodes)
9868 std::vector< std::vector<int> > intersectEdge1, colinear2, subDiv2;
9869 std::vector<double> addCoo,addCoordsQuadratic; // coordinates of newly created nodes
9870 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
9871 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
9873 // Build desc connectivity
9874 DataArrayInt *desc1(DataArrayInt::New()),*descIndx1(DataArrayInt::New()),*revDesc1(DataArrayInt::New()),*revDescIndx1(DataArrayInt::New());
9875 MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(revDesc1),dd4(revDescIndx1);
9876 MCAuto<MEDCouplingUMesh> m1Desc(mesh2D->buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1));
9877 std::map<int,int> mergedNodes;
9878 Intersect1DMeshes(m1Desc,mesh1D,eps,intersectEdge1,colinear2,subDiv2,addCoo,mergedNodes);
9879 // use mergeNodes to fix intersectEdge1
9880 for(std::vector< std::vector<int> >::iterator it0=intersectEdge1.begin();it0!=intersectEdge1.end();it0++)
9882 std::size_t n((*it0).size()/2);
9883 int eltStart((*it0)[0]),eltEnd((*it0)[2*n-1]);
9884 std::map<int,int>::const_iterator it1;
9885 it1=mergedNodes.find(eltStart);
9886 if(it1!=mergedNodes.end())
9887 (*it0)[0]=(*it1).second;
9888 it1=mergedNodes.find(eltEnd);
9889 if(it1!=mergedNodes.end())
9890 (*it0)[2*n-1]=(*it1).second;
9893 MCAuto<DataArrayDouble> addCooDa(DataArrayDouble::New());
9894 addCooDa->useArray(&addCoo[0],false,C_DEALLOC,(int)addCoo.size()/2,2);
9895 // Step 2: re-order newly created nodes according to the ordering found in m2
9896 std::vector< std::vector<int> > intersectEdge2;
9897 BuildIntersectEdges(m1Desc,mesh1D,addCoo,subDiv2,intersectEdge2);
9899 // Step 3: compute splitMesh1D
9900 MCAuto<DataArrayInt> idsInRet1Colinear,idsInDescMesh2DForIdsInRetColinear;
9901 MCAuto<DataArrayInt> ret2(DataArrayInt::New()); ret2->alloc(0,1);
9902 MCAuto<MEDCouplingUMesh> ret1(BuildMesh1DCutFrom(mesh1D,intersectEdge2,mesh2D->getCoords(),addCoo,mergedNodes,colinear2,intersectEdge1,
9903 idsInRet1Colinear,idsInDescMesh2DForIdsInRetColinear));
9904 MCAuto<DataArrayInt> ret3(DataArrayInt::New()); ret3->alloc(ret1->getNumberOfCells()*2,1); ret3->fillWithValue(std::numeric_limits<int>::max()); ret3->rearrange(2);
9905 MCAuto<DataArrayInt> idsInRet1NotColinear(idsInRet1Colinear->buildComplement(ret1->getNumberOfCells()));
9906 // deal with cells in mesh2D that are not cut but only some of their edges are
9907 MCAuto<DataArrayInt> idsInDesc2DToBeRefined(idsInDescMesh2DForIdsInRetColinear->deepCopy());
9908 idsInDesc2DToBeRefined->abs(); idsInDesc2DToBeRefined->applyLin(1,-1);
9909 idsInDesc2DToBeRefined=idsInDesc2DToBeRefined->buildUnique();
9910 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
9911 if(!idsInDesc2DToBeRefined->empty())
9913 DataArrayInt *out0(0),*outi0(0);
9914 MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
9915 MCAuto<DataArrayInt> outi0s(outi0);
9917 out0s=out0s->buildUnique();
9921 MCAuto<MEDCouplingUMesh> ret1NonCol(static_cast<MEDCouplingUMesh *>(ret1->buildPartOfMySelf(idsInRet1NotColinear->begin(),idsInRet1NotColinear->end())));
9922 MCAuto<DataArrayDouble> baryRet1(ret1NonCol->computeCellCenterOfMass());
9923 MCAuto<DataArrayInt> elts,eltsIndex;
9924 mesh2D->getCellsContainingPoints(baryRet1->begin(),baryRet1->getNumberOfTuples(),eps,elts,eltsIndex);
9925 MCAuto<DataArrayInt> eltsIndex2(eltsIndex->deltaShiftIndex());
9926 MCAuto<DataArrayInt> eltsIndex3(eltsIndex2->findIdsEqual(1));
9927 if(eltsIndex2->count(0)+eltsIndex3->getNumberOfTuples()!=ret1NonCol->getNumberOfCells())
9928 throw INTERP_KERNEL::Exception("Intersect2DMeshWith1DLine : internal error 1 !");
9929 MCAuto<DataArrayInt> cellsToBeModified(elts->buildUnique());
9930 MCAuto<DataArrayInt> untouchedCells(cellsToBeModified->buildComplement(mesh2D->getNumberOfCells()));
9931 if((DataArrayInt *)out0s)
9932 untouchedCells=untouchedCells->buildSubstraction(out0s);//if some edges in ret1 are colinear to descending mesh of mesh2D remove cells from untouched one
9933 std::vector< MCAuto<MEDCouplingUMesh> > outMesh2DSplit;
9934 // OK all is ready to insert in ret2 mesh
9935 if(!untouchedCells->empty())
9936 {// the most easy part, cells in mesh2D not impacted at all
9937 outMesh2DSplit.push_back(static_cast<MEDCouplingUMesh *>(mesh2D->buildPartOfMySelf(untouchedCells->begin(),untouchedCells->end())));
9938 outMesh2DSplit.back()->setCoords(ret1->getCoords());
9939 ret2->pushBackValsSilent(untouchedCells->begin(),untouchedCells->end());
9941 if((DataArrayInt *)out0s)
9942 {// here dealing with cells in out0s but not in cellsToBeModified
9943 MCAuto<DataArrayInt> fewModifiedCells(out0s->buildSubstraction(cellsToBeModified));
9944 const int *rdptr(dd3->begin()),*rdiptr(dd4->begin()),*dptr(dd1->begin()),*diptr(dd2->begin());
9945 for(const int *it=fewModifiedCells->begin();it!=fewModifiedCells->end();it++)
9947 outMesh2DSplit.push_back(BuildRefined2DCell(ret1->getCoords(),mesh2D,*it,dptr+diptr[*it],dptr+diptr[*it+1],intersectEdge1));
9948 ret1->setCoords(outMesh2DSplit.back()->getCoords());
9950 int offset(ret2->getNumberOfTuples());
9951 ret2->pushBackValsSilent(fewModifiedCells->begin(),fewModifiedCells->end());
9952 MCAuto<DataArrayInt> partOfRet3(DataArrayInt::New()); partOfRet3->alloc(2*idsInRet1Colinear->getNumberOfTuples(),1);
9953 partOfRet3->fillWithValue(std::numeric_limits<int>::max()); partOfRet3->rearrange(2);
9954 int kk(0),*ret3ptr(partOfRet3->getPointer());
9955 for(const int *it=idsInDescMesh2DForIdsInRetColinear->begin();it!=idsInDescMesh2DForIdsInRetColinear->end();it++,kk++)
9957 int faceId(std::abs(*it)-1);
9958 for(const int *it2=rdptr+rdiptr[faceId];it2!=rdptr+rdiptr[faceId+1];it2++)
9960 int tmp(fewModifiedCells->findIdFirstEqual(*it2));
9963 if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],-(*it))!=dptr+diptr[*it2+1])
9964 ret3ptr[2*kk]=tmp+offset;
9965 if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],(*it))!=dptr+diptr[*it2+1])
9966 ret3ptr[2*kk+1]=tmp+offset;
9969 {//the current edge is shared by a 2D cell that will be split just after
9970 if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],-(*it))!=dptr+diptr[*it2+1])
9971 ret3ptr[2*kk]=-(*it2+1);
9972 if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],(*it))!=dptr+diptr[*it2+1])
9973 ret3ptr[2*kk+1]=-(*it2+1);
9977 m1Desc->setCoords(ret1->getCoords());
9978 ret1NonCol->setCoords(ret1->getCoords());
9979 ret3->setPartOfValues3(partOfRet3,idsInRet1Colinear->begin(),idsInRet1Colinear->end(),0,2,1,true);
9980 if(!outMesh2DSplit.empty())
9982 DataArrayDouble *da(outMesh2DSplit.back()->getCoords());
9983 for(std::vector< MCAuto<MEDCouplingUMesh> >::iterator itt=outMesh2DSplit.begin();itt!=outMesh2DSplit.end();itt++)
9984 (*itt)->setCoords(da);
9987 cellsToBeModified=cellsToBeModified->buildUniqueNotSorted();
9988 for(const int *it=cellsToBeModified->begin();it!=cellsToBeModified->end();it++)
9990 MCAuto<DataArrayInt> idsNonColPerCell(elts->findIdsEqual(*it));
9991 idsNonColPerCell->transformWithIndArr(eltsIndex3->begin(),eltsIndex3->end());
9992 MCAuto<DataArrayInt> idsNonColPerCell2(idsInRet1NotColinear->selectByTupleId(idsNonColPerCell->begin(),idsNonColPerCell->end()));
9993 MCAuto<MEDCouplingUMesh> partOfMesh1CuttingCur2DCell(static_cast<MEDCouplingUMesh *>(ret1NonCol->buildPartOfMySelf(idsNonColPerCell->begin(),idsNonColPerCell->end())));
9994 MCAuto<DataArrayInt> partOfRet3;
9995 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));
9996 ret3->setPartOfValues3(partOfRet3,idsNonColPerCell2->begin(),idsNonColPerCell2->end(),0,2,1,true);
9997 outMesh2DSplit.push_back(splitOfOneCell);
9998 for(int i=0;i<splitOfOneCell->getNumberOfCells();i++)
9999 ret2->pushBackSilent(*it);
10002 std::size_t nbOfMeshes(outMesh2DSplit.size());
10003 std::vector<const MEDCouplingUMesh *> tmp(nbOfMeshes);
10004 for(std::size_t i=0;i<nbOfMeshes;i++)
10005 tmp[i]=outMesh2DSplit[i];
10007 ret1->getCoords()->setInfoOnComponents(compNames);
10008 MCAuto<MEDCouplingUMesh> ret2D(MEDCouplingUMesh::MergeUMeshesOnSameCoords(tmp));
10009 // To finish - filter ret3 - std::numeric_limits<int>::max() -> -1 - negate values must be resolved.
10010 ret3->rearrange(1);
10011 MCAuto<DataArrayInt> edgesToDealWith(ret3->findIdsStricltyNegative());
10012 for(const int *it=edgesToDealWith->begin();it!=edgesToDealWith->end();it++)
10014 int old2DCellId(-ret3->getIJ(*it,0)-1);
10015 MCAuto<DataArrayInt> candidates(ret2->findIdsEqual(old2DCellId));
10016 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
10018 ret3->changeValue(std::numeric_limits<int>::max(),-1);
10019 ret3->rearrange(2);
10021 splitMesh1D=ret1.retn();
10022 splitMesh2D=ret2D.retn();
10023 cellIdInMesh2D=ret2.retn();
10024 cellIdInMesh1D=ret3.retn();
10028 * Private. Third step of the partitioning algorithm (Intersect2DMeshes): reconstruct full 2D cells from the
10029 * (newly created) nodes corresponding to the edge intersections.
10031 * @param[out] cr, crI connectivity of the resulting mesh
10032 * @param[out] cNb1, cNb2 correspondance arrays giving for the merged mesh the initial cells IDs in m1 / m2
10033 * TODO: describe input parameters
10035 void MEDCouplingUMesh::BuildIntersecting2DCellsFromEdges(double eps, const MEDCouplingUMesh *m1, const int *desc1, const int *descIndx1,
10036 const std::vector<std::vector<int> >& intesctEdges1, const std::vector< std::vector<int> >& colinear2,
10037 const MEDCouplingUMesh *m2, const int *desc2, const int *descIndx2, const std::vector<std::vector<int> >& intesctEdges2,
10038 const std::vector<double>& addCoords,
10039 std::vector<double>& addCoordsQuadratic, std::vector<int>& cr, std::vector<int>& crI, std::vector<int>& cNb1, std::vector<int>& cNb2)
10041 static const int SPACEDIM=2;
10042 const double *coo1(m1->getCoords()->getConstPointer());
10043 const int *conn1(m1->getNodalConnectivity()->getConstPointer()),*connI1(m1->getNodalConnectivityIndex()->getConstPointer());
10044 int offset1(m1->getNumberOfNodes());
10045 const double *coo2(m2->getCoords()->getConstPointer());
10046 const int *conn2(m2->getNodalConnectivity()->getConstPointer()),*connI2(m2->getNodalConnectivityIndex()->getConstPointer());
10047 int offset2(offset1+m2->getNumberOfNodes());
10048 int offset3(offset2+((int)addCoords.size())/2);
10049 MCAuto<DataArrayDouble> bbox1Arr(m1->getBoundingBoxForBBTree()),bbox2Arr(m2->getBoundingBoxForBBTree());
10050 const double *bbox1(bbox1Arr->begin()),*bbox2(bbox2Arr->begin());
10051 // Here a BBTree on 2D-cells, not on segments:
10052 BBTree<SPACEDIM,int> myTree(bbox2,0,0,m2->getNumberOfCells(),eps);
10053 int ncell1(m1->getNumberOfCells());
10055 for(int i=0;i<ncell1;i++)
10057 std::vector<int> candidates2;
10058 myTree.getIntersectingElems(bbox1+i*2*SPACEDIM,candidates2);
10059 std::map<INTERP_KERNEL::Node *,int> mapp;
10060 std::map<int,INTERP_KERNEL::Node *> mappRev;
10061 INTERP_KERNEL::QuadraticPolygon pol1;
10062 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn1[connI1[i]];
10063 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
10064 // Populate mapp and mappRev with nodes from the current cell (i) from mesh1 - this also builds the Node* objects:
10065 MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,/* output */mapp,mappRev);
10066 // pol1 is the full cell from mesh2, in QP format, with all the additional intersecting nodes.
10067 pol1.buildFromCrudeDataArray(mappRev,cm.isQuadratic(),conn1+connI1[i]+1,coo1,
10068 desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1);
10070 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
10071 std::set<INTERP_KERNEL::Edge *> edgesBoundary2;// store all edges that are on boundary of (pol2 intersect pol1) minus edges on pol1.
10072 INTERP_KERNEL::IteratorOnComposedEdge it1(&pol1);
10073 for(it1.first();!it1.finished();it1.next())
10074 edges1.insert(it1.current()->getPtr());
10076 std::map<int,std::vector<INTERP_KERNEL::ElementaryEdge *> > edgesIn2ForShare; // common edges
10077 std::vector<INTERP_KERNEL::QuadraticPolygon> pol2s(candidates2.size());
10079 for(std::vector<int>::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++,ii++)
10081 INTERP_KERNEL::NormalizedCellType typ2=(INTERP_KERNEL::NormalizedCellType)conn2[connI2[*it2]];
10082 const INTERP_KERNEL::CellModel& cm2=INTERP_KERNEL::CellModel::GetCellModel(typ2);
10083 // Complete mapping with elements coming from the current cell it2 in mesh2:
10084 MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,/* output */mapp,mappRev);
10085 // pol2 is the new QP in the final merged result.
10086 pol2s[ii].buildFromCrudeDataArray2(mappRev,cm2.isQuadratic(),conn2+connI2[*it2]+1,coo2,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,
10087 pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2, /* output */ edgesIn2ForShare);
10090 for(std::vector<int>::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++,ii++)
10092 INTERP_KERNEL::ComposedEdge::InitLocationsWithOther(pol1,pol2s[ii]);
10093 pol2s[ii].updateLocOfEdgeFromCrudeDataArray2(desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2);
10094 //MEDCouplingUMeshAssignOnLoc(pol1,pol2,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,colinear2);
10095 pol1.buildPartitionsAbs(pol2s[ii],edges1,edgesBoundary2,mapp,i,*it2,offset3,addCoordsQuadratic,cr,crI,cNb1,cNb2);
10097 // Deals with remaining (non-consumed) edges from m1: these are the edges that were never touched
10098 // by m2 but that we still want to keep in the final result.
10099 if(!edges1.empty())
10103 INTERP_KERNEL::QuadraticPolygon::ComputeResidual(pol1,edges1,edgesBoundary2,mapp,offset3,i,addCoordsQuadratic,cr,crI,cNb1,cNb2);
10105 catch(INTERP_KERNEL::Exception& e)
10107 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();
10108 throw INTERP_KERNEL::Exception(oss.str().c_str());
10111 for(std::map<int,INTERP_KERNEL::Node *>::const_iterator it=mappRev.begin();it!=mappRev.end();it++)
10112 (*it).second->decrRef();
10117 * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
10118 * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
10119 * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
10120 * The caller is to deal with the resulting DataArrayInt.
10121 * \throw If the coordinate array is not set.
10122 * \throw If the nodal connectivity of the cells is not defined.
10123 * \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
10124 * \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
10126 * \sa DataArrayInt::sortEachPairToMakeALinkedList
10128 DataArrayInt *MEDCouplingUMesh::orderConsecutiveCells1D() const
10130 checkFullyDefined();
10131 if(getMeshDimension()!=1)
10132 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
10134 // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
10135 MCAuto<DataArrayInt> _d(DataArrayInt::New()),_dI(DataArrayInt::New());
10136 MCAuto<DataArrayInt> _rD(DataArrayInt::New()),_rDI(DataArrayInt::New());
10137 MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
10138 const int *d(_d->getConstPointer()), *dI(_dI->getConstPointer());
10139 const int *rD(_rD->getConstPointer()), *rDI(_rDI->getConstPointer());
10140 MCAuto<DataArrayInt> _dsi(_rDI->deltaShiftIndex());
10141 const int * dsi(_dsi->getConstPointer());
10142 MCAuto<DataArrayInt> dsii = _dsi->findIdsNotInRange(0,3);
10144 if (dsii->getNumberOfTuples())
10145 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
10147 int nc(getNumberOfCells());
10148 MCAuto<DataArrayInt> result(DataArrayInt::New());
10149 result->alloc(nc,1);
10151 // set of edges not used so far
10152 std::set<int> edgeSet;
10153 for (int i=0; i<nc; edgeSet.insert(i), i++);
10157 // while we have points with only one neighbor segments
10160 std::list<int> linePiece;
10161 // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
10162 for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
10164 // Fill the list forward (resp. backward) from the start segment:
10165 int activeSeg = startSeg;
10166 int prevPointId = -20;
10168 while (!edgeSet.empty())
10170 if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
10173 linePiece.push_back(activeSeg);
10175 linePiece.push_front(activeSeg);
10176 edgeSet.erase(activeSeg);
10179 int ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
10180 ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
10181 if (dsi[ptId] == 1) // hitting the end of the line
10183 prevPointId = ptId;
10184 int seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
10185 activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
10188 // Done, save final piece into DA:
10189 std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
10190 newIdx += linePiece.size();
10192 // identify next valid start segment (one which is not consumed)
10193 if(!edgeSet.empty())
10194 startSeg = *(edgeSet.begin());
10196 while (!edgeSet.empty());
10197 return result.retn();
10202 void IKGeo2DInternalMapper2(INTERP_KERNEL::Node *n, const std::map<MCAuto<INTERP_KERNEL::Node>,int>& m, int forbVal0, int forbVal1, std::vector<int>& isect)
10204 MCAuto<INTERP_KERNEL::Node> nTmp(n); nTmp->incrRef();
10205 std::map<MCAuto<INTERP_KERNEL::Node>,int>::const_iterator it(m.find(nTmp));
10207 throw INTERP_KERNEL::Exception("Internal error in remapping !");
10208 int v((*it).second);
10209 if(v==forbVal0 || v==forbVal1)
10211 if(std::find(isect.begin(),isect.end(),v)==isect.end())
10212 isect.push_back(v);
10215 bool IKGeo2DInternalMapper(const INTERP_KERNEL::ComposedEdge& c, const std::map<MCAuto<INTERP_KERNEL::Node>,int>& m, int forbVal0, int forbVal1, std::vector<int>& isect)
10220 bool presenceOfOn(false);
10221 for(int i=0;i<sz;i++)
10223 INTERP_KERNEL::ElementaryEdge *e(c[i]);
10224 if(e->getLoc()!=INTERP_KERNEL::FULL_ON_1)
10226 IKGeo2DInternalMapper2(e->getStartNode(),m,forbVal0,forbVal1,isect);
10227 IKGeo2DInternalMapper2(e->getEndNode(),m,forbVal0,forbVal1,isect);
10229 return presenceOfOn;
10235 * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
10236 * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
10237 * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
10238 * a minimal creation of new nodes is wanted.
10239 * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
10240 * nodes if a SEG3 is split without information of middle.
10241 * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
10242 * avoid to have a non conform mesh.
10244 * \return int - the number of new nodes created (in most of cases 0).
10246 * \throw If \a this is not coherent.
10247 * \throw If \a this has not spaceDim equal to 2.
10248 * \throw If \a this has not meshDim equal to 2.
10249 * \throw If some subcells needed to be split are orphan.
10250 * \sa MEDCouplingUMesh::conformize2D
10252 int MEDCouplingUMesh::split2DCells(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *midOpt, const DataArrayInt *midOptI)
10254 if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
10255 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
10256 desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
10257 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10258 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10259 if(midOpt==0 && midOptI==0)
10261 split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
10264 else if(midOpt!=0 && midOptI!=0)
10265 return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
10267 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
10271 * \b WARNING this method is \b potentially \b non \b const (if returned array is empty).
10272 * \b WARNING this method lead to have a non geometric type sorted mesh (for MED file users) !
10273 * 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
10274 * 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).
10275 * 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.
10277 * Whatever the returned value, this method does not alter the order of cells in \a this neither the orientation of cells.
10278 * The modified cells, if any, are systematically declared as NORM_POLYGON or NORM_QPOLYG depending on the initial quadraticness of geometric type.
10280 * This method expects that \b this has a meshDim equal 2 and spaceDim equal to 2 too.
10281 * This method expects that all nodes in \a this are not closer than \a eps.
10282 * If it is not the case you can invoke MEDCouplingUMesh::mergeNodes before calling this method.
10284 * \param [in] eps the relative error to detect merged edges.
10285 * \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
10286 * that the user is expected to deal with.
10288 * \throw If \a this is not coherent.
10289 * \throw If \a this has not spaceDim equal to 2.
10290 * \throw If \a this has not meshDim equal to 2.
10291 * \sa MEDCouplingUMesh::mergeNodes, MEDCouplingUMesh::split2DCells
10293 DataArrayInt *MEDCouplingUMesh::conformize2D(double eps)
10295 static const int SPACEDIM=2;
10296 checkConsistencyLight();
10297 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10298 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::conformize2D : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10299 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
10300 MCAuto<MEDCouplingUMesh> mDesc(buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));
10301 const int *c(mDesc->getNodalConnectivity()->getConstPointer()),*ci(mDesc->getNodalConnectivityIndex()->getConstPointer()),*rd(revDesc1->getConstPointer()),*rdi(revDescIndx1->getConstPointer());
10302 MCAuto<DataArrayDouble> bboxArr(mDesc->getBoundingBoxForBBTree());
10303 const double *bbox(bboxArr->begin()),*coords(getCoords()->begin());
10304 int nCell(getNumberOfCells()),nDescCell(mDesc->getNumberOfCells());
10305 std::vector< std::vector<int> > intersectEdge(nDescCell),overlapEdge(nDescCell);
10306 std::vector<double> addCoo;
10307 BBTree<SPACEDIM,int> myTree(bbox,0,0,nDescCell,-eps);
10308 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10309 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10310 for(int i=0;i<nDescCell;i++)
10312 std::vector<int> candidates;
10313 myTree.getIntersectingElems(bbox+i*2*SPACEDIM,candidates);
10314 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
10317 std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
10318 INTERP_KERNEL::Edge *e1(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coords,m)),
10319 *e2(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[*it]],c+ci[*it]+1,coords,m));
10320 INTERP_KERNEL::MergePoints merge;
10321 INTERP_KERNEL::QuadraticPolygon c1,c2;
10322 e1->intersectWith(e2,merge,c1,c2);
10323 e1->decrRef(); e2->decrRef();
10324 if(IKGeo2DInternalMapper(c1,m,c[ci[i]+1],c[ci[i]+2],intersectEdge[i]))
10325 overlapEdge[i].push_back(*it);
10326 if(IKGeo2DInternalMapper(c2,m,c[ci[*it]+1],c[ci[*it]+2],intersectEdge[*it]))
10327 overlapEdge[*it].push_back(i);
10330 // splitting done. sort intersect point in intersectEdge.
10331 std::vector< std::vector<int> > middle(nDescCell);
10332 int nbOf2DCellsToBeSplit(0);
10333 bool middleNeedsToBeUsed(false);
10334 std::vector<bool> cells2DToTreat(nDescCell,false);
10335 for(int i=0;i<nDescCell;i++)
10337 std::vector<int>& isect(intersectEdge[i]);
10338 int sz((int)isect.size());
10341 std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
10342 INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coords,m));
10343 e->sortSubNodesAbs(coords,isect);
10348 int idx0(rdi[i]),idx1(rdi[i+1]);
10350 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::conformize2D : internal error #0 !");
10351 if(!cells2DToTreat[rd[idx0]])
10353 cells2DToTreat[rd[idx0]]=true;
10354 nbOf2DCellsToBeSplit++;
10356 // try to reuse at most eventual 'middle' of SEG3
10357 std::vector<int>& mid(middle[i]);
10358 mid.resize(sz+1,-1);
10359 if((INTERP_KERNEL::NormalizedCellType)c[ci[i]]==INTERP_KERNEL::NORM_SEG3)
10361 middleNeedsToBeUsed=true;
10362 const std::vector<int>& candidates(overlapEdge[i]);
10363 std::vector<int> trueCandidates;
10364 for(std::vector<int>::const_iterator itc=candidates.begin();itc!=candidates.end();itc++)
10365 if((INTERP_KERNEL::NormalizedCellType)c[ci[*itc]]==INTERP_KERNEL::NORM_SEG3)
10366 trueCandidates.push_back(*itc);
10367 int stNode(c[ci[i]+1]),endNode(isect[0]);
10368 for(int j=0;j<sz+1;j++)
10370 for(std::vector<int>::const_iterator itc=trueCandidates.begin();itc!=trueCandidates.end();itc++)
10372 int tmpSt(c[ci[*itc]+1]),tmpEnd(c[ci[*itc]+2]);
10373 if((tmpSt==stNode && tmpEnd==endNode) || (tmpSt==endNode && tmpEnd==stNode))
10374 { mid[j]=*itc; break; }
10377 endNode=j<sz-1?isect[j+1]:c[ci[i]+2];
10382 MCAuto<DataArrayInt> ret(DataArrayInt::New()),notRet(DataArrayInt::New()); ret->alloc(nbOf2DCellsToBeSplit,1);
10383 if(nbOf2DCellsToBeSplit==0)
10386 int *retPtr(ret->getPointer());
10387 for(int i=0;i<nCell;i++)
10388 if(cells2DToTreat[i])
10391 MCAuto<DataArrayInt> mSafe,nSafe,oSafe,pSafe,qSafe,rSafe;
10392 DataArrayInt *m(0),*n(0),*o(0),*p(0),*q(0),*r(0);
10393 MEDCouplingUMesh::ExtractFromIndexedArrays(ret->begin(),ret->end(),desc1,descIndx1,m,n); mSafe=m; nSafe=n;
10394 DataArrayInt::PutIntoToSkylineFrmt(intersectEdge,o,p); oSafe=o; pSafe=p;
10395 if(middleNeedsToBeUsed)
10396 { DataArrayInt::PutIntoToSkylineFrmt(middle,q,r); qSafe=q; rSafe=r; }
10397 MCAuto<MEDCouplingUMesh> modif(static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(ret->begin(),ret->end(),true)));
10398 int nbOfNodesCreated(modif->split2DCells(mSafe,nSafe,oSafe,pSafe,qSafe,rSafe));
10399 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.
10400 setPartOfMySelf(ret->begin(),ret->end(),*modif);
10402 bool areNodesMerged; int newNbOfNodes;
10403 if(nbOfNodesCreated!=0)
10404 MCAuto<DataArrayInt> tmp(mergeNodes(eps,areNodesMerged,newNbOfNodes));
10410 * 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.
10411 * 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).
10412 * 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
10413 * to invoke MEDCouplingUMesh::mergeNodes and MEDCouplingUMesh::conformize2D right after this call.
10414 * 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
10415 * new nodes for center of merged edges is are systematically created and appended at the end of the previously existing nodes.
10417 * 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
10418 * using new instance, idem for coordinates.
10420 * 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.
10422 * \return DataArrayInt * - The list of cellIds in \a this that have at least one edge colinearized.
10424 * \throw If \a this is not coherent.
10425 * \throw If \a this has not spaceDim equal to 2.
10426 * \throw If \a this has not meshDim equal to 2.
10428 * \sa MEDCouplingUMesh::conformize2D, MEDCouplingUMesh::mergeNodes, MEDCouplingUMesh::convexEnvelop2D.
10430 DataArrayInt *MEDCouplingUMesh::colinearize2D(double eps)
10432 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
10433 checkConsistencyLight();
10434 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10435 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::colinearize2D : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10436 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10437 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10438 int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
10439 const int *cptr(_nodal_connec->begin()),*ciptr(_nodal_connec_index->begin());
10440 MCAuto<DataArrayInt> newc(DataArrayInt::New()),newci(DataArrayInt::New()); newci->alloc(nbOfCells+1,1); newc->alloc(0,1); newci->setIJ(0,0,0);
10441 MCAuto<DataArrayDouble> appendedCoords(DataArrayDouble::New()); appendedCoords->alloc(0,1);//1 not 2 it is not a bug.
10442 const double *coords(_coords->begin());
10443 int *newciptr(newci->getPointer());
10444 for(int i=0;i<nbOfCells;i++,newciptr++,ciptr++)
10446 if(Colinearize2DCell(coords,cptr+ciptr[0],cptr+ciptr[1],nbOfNodes,newc,appendedCoords))
10447 ret->pushBackSilent(i);
10448 newciptr[1]=newc->getNumberOfTuples();
10453 if(!appendedCoords->empty())
10455 appendedCoords->rearrange(2);
10456 MCAuto<DataArrayDouble> newCoords(DataArrayDouble::Aggregate(getCoords(),appendedCoords));//treat info on components
10458 setCoords(newCoords);
10461 setConnectivity(newc,newci,true);
10466 * \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.
10467 * 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.
10468 * And for each j in [1,n) intersect[i][2*(j-1)+1]==intersect[i][2*j].
10469 * \param [out] subDiv2 - for each cell in \a m2Desc returns nodes that split it using convention \a m1Desc first, then \a m2Desc, then addCoo
10470 * \param [out] colinear2 - for each cell in \a m2Desc returns the edges in \a m1Desc that are colinear to it.
10471 * \param [out] addCoo - nodes to be append at the end
10472 * \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.
10474 void MEDCouplingUMesh::Intersect1DMeshes(const MEDCouplingUMesh *m1Desc, const MEDCouplingUMesh *m2Desc, double eps,
10475 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)
10477 static const int SPACEDIM=2;
10478 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10479 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10480 const int *c1(m1Desc->getNodalConnectivity()->getConstPointer()),*ci1(m1Desc->getNodalConnectivityIndex()->getConstPointer());
10481 // Build BB tree of all edges in the tool mesh (second mesh)
10482 MCAuto<DataArrayDouble> bbox1Arr(m1Desc->getBoundingBoxForBBTree()),bbox2Arr(m2Desc->getBoundingBoxForBBTree());
10483 const double *bbox1(bbox1Arr->begin()),*bbox2(bbox2Arr->begin());
10484 int nDescCell1(m1Desc->getNumberOfCells()),nDescCell2(m2Desc->getNumberOfCells());
10485 intersectEdge1.resize(nDescCell1);
10486 colinear2.resize(nDescCell2);
10487 subDiv2.resize(nDescCell2);
10488 BBTree<SPACEDIM,int> myTree(bbox2,0,0,m2Desc->getNumberOfCells(),-eps);
10490 std::vector<int> candidates1(1);
10491 int offset1(m1Desc->getNumberOfNodes());
10492 int offset2(offset1+m2Desc->getNumberOfNodes());
10493 for(int i=0;i<nDescCell1;i++) // for all edges in the first mesh
10495 std::vector<int> candidates2; // edges of mesh2 candidate for intersection
10496 myTree.getIntersectingElems(bbox1+i*2*SPACEDIM,candidates2);
10497 if(!candidates2.empty()) // candidates2 holds edges from the second mesh potentially intersecting current edge i in mesh1
10499 std::map<INTERP_KERNEL::Node *,int> map1,map2;
10500 // pol2 is not necessarily a closed polygon: just a set of (quadratic) edges (same as candidates2) in the Geometric DS format
10501 INTERP_KERNEL::QuadraticPolygon *pol2=MEDCouplingUMeshBuildQPFromMesh(m2Desc,candidates2,map2);
10503 INTERP_KERNEL::QuadraticPolygon *pol1=MEDCouplingUMeshBuildQPFromMesh(m1Desc,candidates1,map1);
10504 // 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
10505 // This trick guarantees that Node * are discriminant (i.e. form a unique identifier)
10506 std::set<INTERP_KERNEL::Node *> nodes;
10507 pol1->getAllNodes(nodes); pol2->getAllNodes(nodes);
10508 std::size_t szz(nodes.size());
10509 std::vector< MCAuto<INTERP_KERNEL::Node> > nodesSafe(szz);
10510 std::set<INTERP_KERNEL::Node *>::const_iterator itt(nodes.begin());
10511 for(std::size_t iii=0;iii<szz;iii++,itt++)
10512 { (*itt)->incrRef(); nodesSafe[iii]=*itt; }
10513 // end of protection
10514 // Performs egde cutting:
10515 pol1->splitAbs(*pol2,map1,map2,offset1,offset2,candidates2,intersectEdge1[i],i,colinear2,subDiv2,addCoo,mergedNodes);
10520 // Copy the edge (take only the two first points, ie discard quadratic point at this stage)
10521 intersectEdge1[i].insert(intersectEdge1[i].end(),c1+ci1[i]+1,c1+ci1[i]+3);
10526 * This method is private and is the first step of Partition of 2D mesh (spaceDim==2 and meshDim==2).
10527 * It builds the descending connectivity of the two meshes, and then using a binary tree
10528 * it computes the edge intersections. This results in new points being created : they're stored in addCoo.
10529 * Documentation about parameters colinear2 and subDiv2 can be found in method QuadraticPolygon::splitAbs().
10531 void MEDCouplingUMesh::IntersectDescending2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2, double eps,
10532 std::vector< std::vector<int> >& intersectEdge1, std::vector< std::vector<int> >& colinear2, std::vector< std::vector<int> >& subDiv2,
10533 MEDCouplingUMesh *& m1Desc, DataArrayInt *&desc1, DataArrayInt *&descIndx1, DataArrayInt *&revDesc1, DataArrayInt *&revDescIndx1,
10534 std::vector<double>& addCoo,
10535 MEDCouplingUMesh *& m2Desc, DataArrayInt *&desc2, DataArrayInt *&descIndx2, DataArrayInt *&revDesc2, DataArrayInt *&revDescIndx2)
10537 // Build desc connectivity
10538 desc1=DataArrayInt::New(); descIndx1=DataArrayInt::New(); revDesc1=DataArrayInt::New(); revDescIndx1=DataArrayInt::New();
10539 desc2=DataArrayInt::New();
10540 descIndx2=DataArrayInt::New();
10541 revDesc2=DataArrayInt::New();
10542 revDescIndx2=DataArrayInt::New();
10543 MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(revDesc1),dd4(revDescIndx1);
10544 MCAuto<DataArrayInt> dd5(desc2),dd6(descIndx2),dd7(revDesc2),dd8(revDescIndx2);
10545 m1Desc=m1->buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1);
10546 m2Desc=m2->buildDescendingConnectivity2(desc2,descIndx2,revDesc2,revDescIndx2);
10547 MCAuto<MEDCouplingUMesh> dd9(m1Desc),dd10(m2Desc);
10548 std::map<int,int> notUsedMap;
10549 Intersect1DMeshes(m1Desc,m2Desc,eps,intersectEdge1,colinear2,subDiv2,addCoo,notUsedMap);
10550 m1Desc->incrRef(); desc1->incrRef(); descIndx1->incrRef(); revDesc1->incrRef(); revDescIndx1->incrRef();
10551 m2Desc->incrRef(); desc2->incrRef(); descIndx2->incrRef(); revDesc2->incrRef(); revDescIndx2->incrRef();
10555 * This method performs the 2nd step of Partition of 2D mesh.
10556 * This method has 4 inputs :
10557 * - a mesh 'm1' with meshDim==1 and a SpaceDim==2
10558 * - a mesh 'm2' with meshDim==1 and a SpaceDim==2
10559 * - subDiv of size 'm2->getNumberOfCells()' that lists for each seg cell in 'm' the splitting node ids randomly sorted.
10560 * 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'
10561 * Nodes end up lying consecutively on a cutted edge.
10562 * \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.
10563 * (Only present for its coords in case of 'subDiv' shares some nodes of 'm1')
10564 * \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.
10565 * \param addCoo input parameter with additional nodes linked to intersection of the 2 meshes.
10566 * \param[out] intersectEdge the same content as subDiv, but correclty oriented.
10568 void MEDCouplingUMesh::BuildIntersectEdges(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2,
10569 const std::vector<double>& addCoo,
10570 const std::vector< std::vector<int> >& subDiv, std::vector< std::vector<int> >& intersectEdge)
10572 int offset1=m1->getNumberOfNodes();
10573 int ncell=m2->getNumberOfCells();
10574 const int *c=m2->getNodalConnectivity()->getConstPointer();
10575 const int *cI=m2->getNodalConnectivityIndex()->getConstPointer();
10576 const double *coo=m2->getCoords()->getConstPointer();
10577 const double *cooBis=m1->getCoords()->getConstPointer();
10578 int offset2=offset1+m2->getNumberOfNodes();
10579 intersectEdge.resize(ncell);
10580 for(int i=0;i<ncell;i++,cI++)
10582 const std::vector<int>& divs=subDiv[i];
10583 int nnode=cI[1]-cI[0]-1;
10584 std::map<int, std::pair<INTERP_KERNEL::Node *,bool> > mapp2;
10585 std::map<INTERP_KERNEL::Node *, int> mapp22;
10586 for(int j=0;j<nnode;j++)
10588 INTERP_KERNEL::Node *nn=new INTERP_KERNEL::Node(coo[2*c[(*cI)+j+1]],coo[2*c[(*cI)+j+1]+1]);
10589 int nnid=c[(*cI)+j+1];
10590 mapp2[nnid]=std::pair<INTERP_KERNEL::Node *,bool>(nn,true);
10591 mapp22[nn]=nnid+offset1;
10593 INTERP_KERNEL::Edge *e=MEDCouplingUMeshBuildQPFromEdge((INTERP_KERNEL::NormalizedCellType)c[*cI],mapp2,c+(*cI)+1);
10594 for(std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >::const_iterator it=mapp2.begin();it!=mapp2.end();it++)
10595 ((*it).second.first)->decrRef();
10596 std::vector<INTERP_KERNEL::Node *> addNodes(divs.size());
10597 std::map<INTERP_KERNEL::Node *,int> mapp3;
10598 for(std::size_t j=0;j<divs.size();j++)
10601 INTERP_KERNEL::Node *tmp=0;
10603 tmp=new INTERP_KERNEL::Node(cooBis[2*id],cooBis[2*id+1]);
10604 else if(id<offset2)
10605 tmp=new INTERP_KERNEL::Node(coo[2*(id-offset1)],coo[2*(id-offset1)+1]);//if it happens, bad news mesh 'm2' is non conform.
10607 tmp=new INTERP_KERNEL::Node(addCoo[2*(id-offset2)],addCoo[2*(id-offset2)+1]);
10611 e->sortIdsAbs(addNodes,mapp22,mapp3,intersectEdge[i]);
10612 for(std::vector<INTERP_KERNEL::Node *>::const_iterator it=addNodes.begin();it!=addNodes.end();it++)
10619 * 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).
10620 * 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
10621 * with a plane. The result will be put in 'cut3DSuf' out parameter.
10622 * \param [in] cut3DCurve input paramter that gives for each 3DCurve cell if it owns fully to the plane or partially.
10623 * \param [out] nodesOnPlane, returns all the nodes that are on the plane.
10624 * \param [in] nodal3DSurf is the nodal connectivity of 3D surf mesh.
10625 * \param [in] nodalIndx3DSurf is the nodal connectivity index of 3D surf mesh.
10626 * \param [in] nodal3DCurve is the nodal connectivity of 3D curve mesh.
10627 * \param [in] nodal3DIndxCurve is the nodal connectivity index of 3D curve mesh.
10628 * \param [in] desc is the descending connectivity 3DSurf->3DCurve
10629 * \param [in] descIndx is the descending connectivity index 3DSurf->3DCurve
10630 * \param [out] cut3DSuf input/output param.
10632 void MEDCouplingUMesh::AssemblyForSplitFrom3DCurve(const std::vector<int>& cut3DCurve, std::vector<int>& nodesOnPlane, const int *nodal3DSurf, const int *nodalIndx3DSurf,
10633 const int *nodal3DCurve, const int *nodalIndx3DCurve,
10634 const int *desc, const int *descIndx,
10635 std::vector< std::pair<int,int> >& cut3DSurf)
10637 std::set<int> nodesOnP(nodesOnPlane.begin(),nodesOnPlane.end());
10638 int nbOf3DSurfCell=(int)cut3DSurf.size();
10639 for(int i=0;i<nbOf3DSurfCell;i++)
10641 std::vector<int> res;
10642 int offset=descIndx[i];
10643 int nbOfSeg=descIndx[i+1]-offset;
10644 for(int j=0;j<nbOfSeg;j++)
10646 int edgeId=desc[offset+j];
10647 int status=cut3DCurve[edgeId];
10651 res.push_back(status);
10654 res.push_back(nodal3DCurve[nodalIndx3DCurve[edgeId]+1]);
10655 res.push_back(nodal3DCurve[nodalIndx3DCurve[edgeId]+2]);
10663 cut3DSurf[i].first=res[0]; cut3DSurf[i].second=res[1];
10669 std::set<int> s1(nodal3DSurf+nodalIndx3DSurf[i]+1,nodal3DSurf+nodalIndx3DSurf[i+1]);
10670 std::set_intersection(nodesOnP.begin(),nodesOnP.end(),s1.begin(),s1.end(),std::back_insert_iterator< std::vector<int> >(res));
10673 cut3DSurf[i].first=res[0]; cut3DSurf[i].second=res[1];
10677 cut3DSurf[i].first=-1; cut3DSurf[i].second=-1;
10682 {// case when plane is on a multi colinear edge of a polyhedron
10683 if((int)res.size()==2*nbOfSeg)
10685 cut3DSurf[i].first=-2; cut3DSurf[i].second=i;
10688 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AssemblyPointsFrom3DCurve : unexpected situation !");
10695 * \a this is expected to be a mesh with spaceDim==3 and meshDim==3. If not an exception will be thrown.
10696 * 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).
10697 * 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
10698 * with a plane. The result will be put in 'nodalRes' 'nodalResIndx' and 'cellIds' out parameters.
10699 * \param cut3DSurf input paramter that gives for each 3DSurf its intersection with plane (result of MEDCouplingUMesh::AssemblyForSplitFrom3DCurve).
10700 * \param desc is the descending connectivity 3D->3DSurf
10701 * \param descIndx is the descending connectivity index 3D->3DSurf
10703 void MEDCouplingUMesh::assemblyForSplitFrom3DSurf(const std::vector< std::pair<int,int> >& cut3DSurf,
10704 const int *desc, const int *descIndx,
10705 DataArrayInt *nodalRes, DataArrayInt *nodalResIndx, DataArrayInt *cellIds) const
10707 checkFullyDefined();
10708 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
10709 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::assemblyForSplitFrom3DSurf works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
10710 const int *nodal3D=_nodal_connec->getConstPointer();
10711 const int *nodalIndx3D=_nodal_connec_index->getConstPointer();
10712 int nbOfCells=getNumberOfCells();
10713 for(int i=0;i<nbOfCells;i++)
10715 std::map<int, std::set<int> > m;
10716 int offset=descIndx[i];
10717 int nbOfFaces=descIndx[i+1]-offset;
10720 for(int j=0;j<nbOfFaces;j++)
10722 const std::pair<int,int>& p=cut3DSurf[desc[offset+j]];
10723 if(p.first!=-1 && p.second!=-1)
10727 start=p.first; end=p.second;
10728 m[p.first].insert(p.second);
10729 m[p.second].insert(p.first);
10733 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodal3D[nodalIndx3D[i]]);
10734 int sz=nodalIndx3D[i+1]-nodalIndx3D[i]-1;
10735 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
10736 INTERP_KERNEL::NormalizedCellType cmsId;
10737 unsigned nbOfNodesSon=cm.fillSonCellNodalConnectivity2(j,nodal3D+nodalIndx3D[i]+1,sz,tmp,cmsId);
10738 start=tmp[0]; end=tmp[nbOfNodesSon-1];
10739 for(unsigned k=0;k<nbOfNodesSon;k++)
10741 m[tmp[k]].insert(tmp[(k+1)%nbOfNodesSon]);
10742 m[tmp[(k+1)%nbOfNodesSon]].insert(tmp[k]);
10749 std::vector<int> conn(1,(int)INTERP_KERNEL::NORM_POLYGON);
10753 std::map<int, std::set<int> >::const_iterator it=m.find(start);
10754 const std::set<int>& s=(*it).second;
10755 std::set<int> s2; s2.insert(prev);
10757 std::set_difference(s.begin(),s.end(),s2.begin(),s2.end(),inserter(s3,s3.begin()));
10760 int val=*s3.begin();
10761 conn.push_back(start);
10768 conn.push_back(end);
10771 nodalRes->insertAtTheEnd(conn.begin(),conn.end());
10772 nodalResIndx->pushBackSilent(nodalRes->getNumberOfTuples());
10773 cellIds->pushBackSilent(i);
10779 * 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
10780 * 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
10781 * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
10782 * 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
10783 * 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.
10785 * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
10787 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const int *nodalConnBg, const int *nodalConnEnd, DataArrayInt *nodalConnecOut)
10789 std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
10792 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
10793 if(cm.getDimension()==2)
10795 const int *node=nodalConnBg+1;
10796 int startNode=*node++;
10797 double refX=coords[2*startNode];
10798 for(;node!=nodalConnEnd;node++)
10800 if(coords[2*(*node)]<refX)
10803 refX=coords[2*startNode];
10806 std::vector<int> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
10810 double angle0=-M_PI/2;
10815 double angleNext=0.;
10816 while(nextNode!=startNode)
10820 for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
10822 if(*node!=tmpOut.back() && *node!=prevNode)
10824 tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
10825 double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
10830 res=angle0-angleM+2.*M_PI;
10839 if(nextNode!=startNode)
10841 angle0=angleNext-M_PI;
10844 prevNode=tmpOut.back();
10845 tmpOut.push_back(nextNode);
10848 std::vector<int> tmp3(2*(sz-1));
10849 std::vector<int>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
10850 std::copy(nodalConnBg+1,nodalConnEnd,it);
10851 if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
10853 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
10856 if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
10858 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
10863 nodalConnecOut->pushBackSilent((int)INTERP_KERNEL::NORM_POLYGON);
10864 nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
10869 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
10872 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
10876 * This method works on an input pair (\b arr, \b arrIndx) where \b arr indexes is in \b arrIndx.
10877 * 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.
10879 * \param [in] idsToRemoveBg begin of set of ids to remove in \b arr (included)
10880 * \param [in] idsToRemoveEnd end of set of ids to remove in \b arr (excluded)
10881 * \param [in,out] arr array in which the remove operation will be done.
10882 * \param [in,out] arrIndx array in the remove operation will modify
10883 * \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])
10884 * \return true if \b arr and \b arrIndx have been modified, false if not.
10886 bool MEDCouplingUMesh::RemoveIdsFromIndexedArrays(const int *idsToRemoveBg, const int *idsToRemoveEnd, DataArrayInt *arr, DataArrayInt *arrIndx, int offsetForRemoval)
10888 if(!arrIndx || !arr)
10889 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : some input arrays are empty !");
10890 if(offsetForRemoval<0)
10891 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : offsetForRemoval should be >=0 !");
10892 std::set<int> s(idsToRemoveBg,idsToRemoveEnd);
10893 int nbOfGrps=arrIndx->getNumberOfTuples()-1;
10894 int *arrIPtr=arrIndx->getPointer();
10896 int previousArrI=0;
10897 const int *arrPtr=arr->getConstPointer();
10898 std::vector<int> arrOut;//no utility to switch to DataArrayInt because copy always needed
10899 for(int i=0;i<nbOfGrps;i++,arrIPtr++)
10901 if(*arrIPtr-previousArrI>offsetForRemoval)
10903 for(const int *work=arrPtr+previousArrI+offsetForRemoval;work!=arrPtr+*arrIPtr;work++)
10905 if(s.find(*work)==s.end())
10906 arrOut.push_back(*work);
10909 previousArrI=*arrIPtr;
10910 *arrIPtr=(int)arrOut.size();
10912 if(arr->getNumberOfTuples()==(int)arrOut.size())
10914 arr->alloc((int)arrOut.size(),1);
10915 std::copy(arrOut.begin(),arrOut.end(),arr->getPointer());
10920 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
10921 * (\ref numbering-indirect).
10922 * This method returns the result of the extraction ( specified by a set of ids in [\b idsOfSelectBg , \b idsOfSelectEnd ) ).
10923 * The selection of extraction is done standardly in new2old format.
10924 * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
10926 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
10927 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
10928 * \param [in] arrIn arr origin array from which the extraction will be done.
10929 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
10930 * \param [out] arrOut the resulting array
10931 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
10932 * \sa MEDCouplingUMesh::ExtractFromIndexedArraysSlice
10934 void MEDCouplingUMesh::ExtractFromIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
10935 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
10937 if(!arrIn || !arrIndxIn)
10938 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input pointer is NULL !");
10939 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
10940 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
10941 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input arrays must have exactly one component !");
10942 std::size_t sz=std::distance(idsOfSelectBg,idsOfSelectEnd);
10943 const int *arrInPtr=arrIn->getConstPointer();
10944 const int *arrIndxPtr=arrIndxIn->getConstPointer();
10945 int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
10947 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
10948 int maxSizeOfArr=arrIn->getNumberOfTuples();
10949 MCAuto<DataArrayInt> arro=DataArrayInt::New();
10950 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
10951 arrIo->alloc((int)(sz+1),1);
10952 const int *idsIt=idsOfSelectBg;
10953 int *work=arrIo->getPointer();
10956 for(std::size_t i=0;i<sz;i++,work++,idsIt++)
10958 if(*idsIt>=0 && *idsIt<nbOfGrps)
10959 lgth+=arrIndxPtr[*idsIt+1]-arrIndxPtr[*idsIt];
10962 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " ! Must be in [0," << nbOfGrps << ") !";
10963 throw INTERP_KERNEL::Exception(oss.str().c_str());
10969 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " and at this pos arrIndxIn[" << *idsIt;
10970 oss << "+1]-arrIndxIn[" << *idsIt << "] < 0 ! The input index array is bugged !";
10971 throw INTERP_KERNEL::Exception(oss.str().c_str());
10974 arro->alloc(lgth,1);
10975 work=arro->getPointer();
10976 idsIt=idsOfSelectBg;
10977 for(std::size_t i=0;i<sz;i++,idsIt++)
10979 if(arrIndxPtr[*idsIt]>=0 && arrIndxPtr[*idsIt+1]<=maxSizeOfArr)
10980 work=std::copy(arrInPtr+arrIndxPtr[*idsIt],arrInPtr+arrIndxPtr[*idsIt+1],work);
10983 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " arrIndx[" << *idsIt << "] must be >= 0 and arrIndx[";
10984 oss << *idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
10985 throw INTERP_KERNEL::Exception(oss.str().c_str());
10988 arrOut=arro.retn();
10989 arrIndexOut=arrIo.retn();
10993 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
10994 * (\ref numbering-indirect).
10995 * 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 ).
10996 * The selection of extraction is done standardly in new2old format.
10997 * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
10999 * \param [in] idsOfSelectStart begin of set of ids of the input extraction (included)
11000 * \param [in] idsOfSelectStop end of set of ids of the input extraction (excluded)
11001 * \param [in] idsOfSelectStep
11002 * \param [in] arrIn arr origin array from which the extraction will be done.
11003 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11004 * \param [out] arrOut the resulting array
11005 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11006 * \sa MEDCouplingUMesh::ExtractFromIndexedArrays
11008 void MEDCouplingUMesh::ExtractFromIndexedArraysSlice(int idsOfSelectStart, int idsOfSelectStop, int idsOfSelectStep, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11009 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11011 if(!arrIn || !arrIndxIn)
11012 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input pointer is NULL !");
11013 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
11014 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
11015 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input arrays must have exactly one component !");
11016 int sz=DataArrayInt::GetNumberOfItemGivenBESRelative(idsOfSelectStart,idsOfSelectStop,idsOfSelectStep,"MEDCouplingUMesh::ExtractFromIndexedArraysSlice : Input slice ");
11017 const int *arrInPtr=arrIn->getConstPointer();
11018 const int *arrIndxPtr=arrIndxIn->getConstPointer();
11019 int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
11021 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
11022 int maxSizeOfArr=arrIn->getNumberOfTuples();
11023 MCAuto<DataArrayInt> arro=DataArrayInt::New();
11024 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11025 arrIo->alloc((int)(sz+1),1);
11026 int idsIt=idsOfSelectStart;
11027 int *work=arrIo->getPointer();
11030 for(int i=0;i<sz;i++,work++,idsIt+=idsOfSelectStep)
11032 if(idsIt>=0 && idsIt<nbOfGrps)
11033 lgth+=arrIndxPtr[idsIt+1]-arrIndxPtr[idsIt];
11036 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " ! Must be in [0," << nbOfGrps << ") !";
11037 throw INTERP_KERNEL::Exception(oss.str().c_str());
11043 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " and at this pos arrIndxIn[" << idsIt;
11044 oss << "+1]-arrIndxIn[" << idsIt << "] < 0 ! The input index array is bugged !";
11045 throw INTERP_KERNEL::Exception(oss.str().c_str());
11048 arro->alloc(lgth,1);
11049 work=arro->getPointer();
11050 idsIt=idsOfSelectStart;
11051 for(int i=0;i<sz;i++,idsIt+=idsOfSelectStep)
11053 if(arrIndxPtr[idsIt]>=0 && arrIndxPtr[idsIt+1]<=maxSizeOfArr)
11054 work=std::copy(arrInPtr+arrIndxPtr[idsIt],arrInPtr+arrIndxPtr[idsIt+1],work);
11057 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " arrIndx[" << idsIt << "] must be >= 0 and arrIndx[";
11058 oss << idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
11059 throw INTERP_KERNEL::Exception(oss.str().c_str());
11062 arrOut=arro.retn();
11063 arrIndexOut=arrIo.retn();
11067 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11068 * 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
11069 * cellIds \b in [ \b idsOfSelectBg , \b idsOfSelectEnd ) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
11070 * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
11072 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
11073 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
11074 * \param [in] arrIn arr origin array from which the extraction will be done.
11075 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11076 * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg, \b idsOfSelectEnd )
11077 * \param [in] srcArrIndex index array of \b srcArr
11078 * \param [out] arrOut the resulting array
11079 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11081 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
11083 void MEDCouplingUMesh::SetPartOfIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11084 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
11085 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11087 if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11088 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArrays : presence of null pointer in input parameter !");
11089 MCAuto<DataArrayInt> arro=DataArrayInt::New();
11090 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11091 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11092 std::vector<bool> v(nbOfTuples,true);
11094 const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11095 const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11096 for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
11098 if(*it>=0 && *it<nbOfTuples)
11101 offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[*it+1]-arrIndxInPtr[*it]);
11105 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArrays : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
11106 throw INTERP_KERNEL::Exception(oss.str().c_str());
11109 srcArrIndexPtr=srcArrIndex->getConstPointer();
11110 arrIo->alloc(nbOfTuples+1,1);
11111 arro->alloc(arrIn->getNumberOfTuples()+offset,1);
11112 const int *arrInPtr=arrIn->getConstPointer();
11113 const int *srcArrPtr=srcArr->getConstPointer();
11114 int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
11115 int *arroPtr=arro->getPointer();
11116 for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
11120 arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
11121 *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
11125 std::size_t pos=std::distance(idsOfSelectBg,std::find(idsOfSelectBg,idsOfSelectEnd,ii));
11126 arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
11127 *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
11130 arrOut=arro.retn();
11131 arrIndexOut=arrIo.retn();
11135 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11136 * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
11138 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
11139 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
11140 * \param [in,out] arrInOut arr origin array from which the extraction will be done.
11141 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11142 * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg , \b idsOfSelectEnd )
11143 * \param [in] srcArrIndex index array of \b srcArr
11145 * \sa MEDCouplingUMesh::SetPartOfIndexedArrays
11147 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(const int *idsOfSelectBg, const int *idsOfSelectEnd, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
11148 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
11150 if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11151 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : presence of null pointer in input parameter !");
11152 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11153 const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11154 const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11155 int *arrInOutPtr=arrInOut->getPointer();
11156 const int *srcArrPtr=srcArr->getConstPointer();
11157 for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
11159 if(*it>=0 && *it<nbOfTuples)
11161 if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[*it+1]-arrIndxInPtr[*it])
11162 std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[*it]);
11165 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] !";
11166 throw INTERP_KERNEL::Exception(oss.str().c_str());
11171 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
11172 throw INTERP_KERNEL::Exception(oss.str().c_str());
11178 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
11179 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
11180 * 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]].
11181 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
11182 * A negative value in \b arrIn means that it is ignored.
11183 * 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.
11185 * \param [in] arrIn arr origin array from which the extraction will be done.
11186 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11187 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
11188 * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
11190 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn)
11192 int seed=0,nbOfDepthPeelingPerformed=0;
11193 return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
11197 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
11198 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
11199 * 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]].
11200 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
11201 * A negative value in \b arrIn means that it is ignored.
11202 * 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.
11203 * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
11204 * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
11205 * \param [in] arrIn arr origin array from which the extraction will be done.
11206 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11207 * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
11208 * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
11209 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
11210 * \sa MEDCouplingUMesh::partitionBySpreadZone
11212 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed)
11214 nbOfDepthPeelingPerformed=0;
11216 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
11217 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11220 DataArrayInt *ret=DataArrayInt::New(); ret->alloc(0,1);
11224 std::vector<bool> fetched(nbOfTuples,false);
11225 return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
11228 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg(std::vector<bool>& fetched, const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed)
11230 nbOfDepthPeelingPerformed=0;
11231 if(!seedBg || !seedEnd || !arrIn || !arrIndxIn)
11232 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg : some input pointer is NULL !");
11233 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11234 std::vector<bool> fetched2(nbOfTuples,false);
11236 for(const int *seedElt=seedBg;seedElt!=seedEnd;seedElt++,i++)
11238 if(*seedElt>=0 && *seedElt<nbOfTuples)
11239 { fetched[*seedElt]=true; fetched2[*seedElt]=true; }
11241 { std::ostringstream oss; oss << "MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg : At pos #" << i << " of seeds value is " << *seedElt << "! Should be in [0," << nbOfTuples << ") !"; throw INTERP_KERNEL::Exception(oss.str().c_str()); }
11243 const int *arrInPtr=arrIn->getConstPointer();
11244 const int *arrIndxPtr=arrIndxIn->getConstPointer();
11245 int targetNbOfDepthPeeling=nbOfDepthPeeling!=-1?nbOfDepthPeeling:std::numeric_limits<int>::max();
11246 std::vector<int> idsToFetch1(seedBg,seedEnd);
11247 std::vector<int> idsToFetch2;
11248 std::vector<int> *idsToFetch=&idsToFetch1;
11249 std::vector<int> *idsToFetchOther=&idsToFetch2;
11250 while(!idsToFetch->empty() && nbOfDepthPeelingPerformed<targetNbOfDepthPeeling)
11252 for(std::vector<int>::const_iterator it=idsToFetch->begin();it!=idsToFetch->end();it++)
11253 for(const int *it2=arrInPtr+arrIndxPtr[*it];it2!=arrInPtr+arrIndxPtr[*it+1];it2++)
11255 { fetched[*it2]=true; fetched2[*it2]=true; idsToFetchOther->push_back(*it2); }
11256 std::swap(idsToFetch,idsToFetchOther);
11257 idsToFetchOther->clear();
11258 nbOfDepthPeelingPerformed++;
11260 int lgth=(int)std::count(fetched2.begin(),fetched2.end(),true);
11262 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(lgth,1);
11263 int *retPtr=ret->getPointer();
11264 for(std::vector<bool>::const_iterator it=fetched2.begin();it!=fetched2.end();it++,i++)
11271 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11272 * 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
11273 * cellIds \b in [\b idsOfSelectBg, \b idsOfSelectEnd) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
11274 * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
11276 * \param [in] start begin of set of ids of the input extraction (included)
11277 * \param [in] end end of set of ids of the input extraction (excluded)
11278 * \param [in] step step of the set of ids in range mode.
11279 * \param [in] arrIn arr origin array from which the extraction will be done.
11280 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11281 * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
11282 * \param [in] srcArrIndex index array of \b srcArr
11283 * \param [out] arrOut the resulting array
11284 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11286 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx MEDCouplingUMesh::SetPartOfIndexedArrays
11288 void MEDCouplingUMesh::SetPartOfIndexedArraysSlice(int start, int end, int step, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11289 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
11290 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11292 if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11293 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSlice : presence of null pointer in input parameter !");
11294 MCAuto<DataArrayInt> arro=DataArrayInt::New();
11295 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11296 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11298 const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11299 const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11300 int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSlice : ");
11302 for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
11304 if(it>=0 && it<nbOfTuples)
11305 offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[it+1]-arrIndxInPtr[it]);
11308 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
11309 throw INTERP_KERNEL::Exception(oss.str().c_str());
11312 srcArrIndexPtr=srcArrIndex->getConstPointer();
11313 arrIo->alloc(nbOfTuples+1,1);
11314 arro->alloc(arrIn->getNumberOfTuples()+offset,1);
11315 const int *arrInPtr=arrIn->getConstPointer();
11316 const int *srcArrPtr=srcArr->getConstPointer();
11317 int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
11318 int *arroPtr=arro->getPointer();
11319 for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
11321 int pos=DataArray::GetPosOfItemGivenBESRelativeNoThrow(ii,start,end,step);
11324 arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
11325 *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
11329 arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
11330 *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
11333 arrOut=arro.retn();
11334 arrIndexOut=arrIo.retn();
11338 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11339 * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
11341 * \param [in] start begin of set of ids of the input extraction (included)
11342 * \param [in] end end of set of ids of the input extraction (excluded)
11343 * \param [in] step step of the set of ids in range mode.
11344 * \param [in,out] arrInOut arr origin array from which the extraction will be done.
11345 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11346 * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
11347 * \param [in] srcArrIndex index array of \b srcArr
11349 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSlice MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
11351 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(int start, int end, int step, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
11352 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
11354 if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11355 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : presence of null pointer in input parameter !");
11356 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11357 const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11358 const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11359 int *arrInOutPtr=arrInOut->getPointer();
11360 const int *srcArrPtr=srcArr->getConstPointer();
11361 int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : ");
11363 for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
11365 if(it>=0 && it<nbOfTuples)
11367 if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[it+1]-arrIndxInPtr[it])
11368 std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[it]);
11371 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " id (idsOfSelectBg[" << i << "]) is " << it << " arrIndxIn[id+1]-arrIndxIn[id]!=srcArrIndex[pos+1]-srcArrIndex[pos] !";
11372 throw INTERP_KERNEL::Exception(oss.str().c_str());
11377 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
11378 throw INTERP_KERNEL::Exception(oss.str().c_str());
11384 * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
11385 * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
11386 * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
11387 * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
11388 * The sum of measure field of returned mesh is equal to the sum of measure field of this.
11390 * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
11392 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
11394 checkFullyDefined();
11395 int mdim=getMeshDimension();
11396 int spaceDim=getSpaceDimension();
11398 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
11399 std::vector<DataArrayInt *> partition=partitionBySpreadZone();
11400 std::vector< MCAuto<DataArrayInt> > partitionAuto; partitionAuto.reserve(partition.size());
11401 std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayInt> > >(partitionAuto));
11402 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
11403 ret->setCoords(getCoords());
11404 ret->allocateCells((int)partition.size());
11406 for(std::vector<DataArrayInt *>::const_iterator it=partition.begin();it!=partition.end();it++)
11408 MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
11409 MCAuto<DataArrayInt> cell;
11413 cell=tmp->buildUnionOf2DMesh();
11416 cell=tmp->buildUnionOf3DMesh();
11419 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
11422 ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->getConstPointer()+1);
11425 ret->finishInsertingCells();
11430 * This method partitions \b this into contiguous zone.
11431 * This method only needs a well defined connectivity. Coordinates are not considered here.
11432 * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
11434 std::vector<DataArrayInt *> MEDCouplingUMesh::partitionBySpreadZone() const
11436 int nbOfCellsCur=getNumberOfCells();
11437 std::vector<DataArrayInt *> ret;
11438 if(nbOfCellsCur<=0)
11440 DataArrayInt *neigh=0,*neighI=0;
11441 computeNeighborsOfCells(neigh,neighI);
11442 MCAuto<DataArrayInt> neighAuto(neigh),neighIAuto(neighI);
11443 std::vector<bool> fetchedCells(nbOfCellsCur,false);
11444 std::vector< MCAuto<DataArrayInt> > ret2;
11446 while(seed<nbOfCellsCur)
11448 int nbOfPeelPerformed=0;
11449 ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,neigh,neighI,-1,nbOfPeelPerformed));
11450 seed=(int)std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false));
11452 for(std::vector< MCAuto<DataArrayInt> >::iterator it=ret2.begin();it!=ret2.end();it++)
11453 ret.push_back((*it).retn());
11458 * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
11459 * newly allocated DataArrayInt instance with 2 components ready to be interpreted as input of DataArrayInt::findRangeIdForEachTuple method.
11461 * \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.
11462 * \return a newly allocated DataArrayInt to be managed by the caller.
11463 * \throw In case of \a code has not the right format (typically of size 3*n)
11465 DataArrayInt *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<int>& code)
11467 MCAuto<DataArrayInt> ret=DataArrayInt::New();
11468 std::size_t nb=code.size()/3;
11469 if(code.size()%3!=0)
11470 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
11471 ret->alloc((int)nb,2);
11472 int *retPtr=ret->getPointer();
11473 for(std::size_t i=0;i<nb;i++,retPtr+=2)
11475 retPtr[0]=code[3*i+2];
11476 retPtr[1]=code[3*i+2]+code[3*i+1];
11482 * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
11483 * All cells in \a this are expected to be linear 3D cells.
11484 * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
11485 * It leads to an increase to number of cells.
11486 * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
11487 * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
11488 * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
11490 * \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.
11491 * For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
11492 * \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.
11493 * \param [out] n2oCells - A new instance of DataArrayInt holding, for each new cell,
11494 * an id of old cell producing it. The caller is to delete this array using
11495 * decrRef() as it is no more needed.
11496 * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
11498 * \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
11499 * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
11501 * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
11502 * \throw If \a this is not fully constituted with linear 3D cells.
11503 * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
11505 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayInt *& n2oCells, int& nbOfAdditionalPoints) const
11507 INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
11508 checkConnectivityFullyDefined();
11509 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
11510 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
11511 int nbOfCells(getNumberOfCells()),nbNodes(getNumberOfNodes());
11512 MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
11513 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfCells,1);
11514 int *retPt(ret->getPointer());
11515 MCAuto<DataArrayInt> newConn(DataArrayInt::New()); newConn->alloc(0,1);
11516 MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
11517 const int *oldc(_nodal_connec->begin());
11518 const int *oldci(_nodal_connec_index->begin());
11519 const double *coords(_coords->begin());
11520 for(int i=0;i<nbOfCells;i++,oldci++,retPt++)
11522 std::vector<int> a; std::vector<double> b;
11523 INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
11524 std::size_t nbOfTet(a.size()/4); *retPt=(int)nbOfTet;
11525 const int *aa(&a[0]);
11528 for(std::vector<int>::iterator it=a.begin();it!=a.end();it++)
11530 *it=(-(*(it))-1+nbNodes);
11531 addPts->insertAtTheEnd(b.begin(),b.end());
11532 nbNodes+=(int)b.size()/3;
11534 for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
11535 newConn->insertAtTheEnd(aa,aa+4);
11537 if(!addPts->empty())
11539 addPts->rearrange(3);
11540 nbOfAdditionalPoints=addPts->getNumberOfTuples();
11541 addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
11542 ret0->setCoords(addPts);
11546 nbOfAdditionalPoints=0;
11547 ret0->setCoords(getCoords());
11549 ret0->setNodalConnectivity(newConn);
11551 ret->computeOffsetsFull();
11552 n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
11553 return ret0.retn();
11557 * 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).
11559 * \sa MEDCouplingUMesh::split2DCells
11561 void MEDCouplingUMesh::split2DCellsLinear(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI)
11563 checkConnectivityFullyDefined();
11564 int ncells(getNumberOfCells()),lgthToReach(getNodalConnectivityArrayLen()+subNodesInSeg->getNumberOfTuples());
11565 MCAuto<DataArrayInt> c(DataArrayInt::New()); c->alloc((std::size_t)lgthToReach);
11566 const int *subPtr(subNodesInSeg->begin()),*subIPtr(subNodesInSegI->begin()),*descPtr(desc->begin()),*descIPtr(descI->begin()),*oldConn(getNodalConnectivity()->begin());
11567 int *cPtr(c->getPointer()),*ciPtr(getNodalConnectivityIndex()->getPointer());
11568 int prevPosOfCi(ciPtr[0]);
11569 for(int i=0;i<ncells;i++,ciPtr++,descIPtr++)
11571 int offset(descIPtr[0]),sz(descIPtr[1]-descIPtr[0]),deltaSz(0);
11572 *cPtr++=(int)INTERP_KERNEL::NORM_POLYGON; *cPtr++=oldConn[prevPosOfCi+1];
11573 for(int j=0;j<sz;j++)
11575 int offset2(subIPtr[descPtr[offset+j]]),sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]);
11576 for(int k=0;k<sz2;k++)
11577 *cPtr++=subPtr[offset2+k];
11579 *cPtr++=oldConn[prevPosOfCi+j+2];
11582 prevPosOfCi=ciPtr[1];
11583 ciPtr[1]=ciPtr[0]+1+sz+deltaSz;//sz==old nb of nodes because (nb of subedges=nb of nodes for polygons)
11586 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCellsLinear : Some of edges to be split are orphan !");
11587 _nodal_connec->decrRef();
11588 _nodal_connec=c.retn(); _types.clear(); _types.insert(INTERP_KERNEL::NORM_POLYGON);
11591 int InternalAddPoint(const INTERP_KERNEL::Edge *e, int id, const double *coo, int startId, int endId, DataArrayDouble& addCoo, int& nodesCnter)
11597 int ret(nodesCnter++);
11599 e->getMiddleOfPoints(coo+2*startId,coo+2*endId,newPt);
11600 addCoo.insertAtTheEnd(newPt,newPt+2);
11605 int InternalAddPointOriented(const INTERP_KERNEL::Edge *e, int id, const double *coo, int startId, int endId, DataArrayDouble& addCoo, int& nodesCnter)
11611 int ret(nodesCnter++);
11613 e->getMiddleOfPointsOriented(coo+2*startId,coo+2*endId,newPt);
11614 addCoo.insertAtTheEnd(newPt,newPt+2);
11622 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)
11625 int trueStart(start>=0?start:nbOfEdges+start);
11626 tmp[0]=linOrArc?(int)INTERP_KERNEL::NORM_QPOLYG:(int)INTERP_KERNEL::NORM_POLYGON; tmp[1]=connBg[trueStart]; tmp[2]=connBg[stp];
11627 newConnOfCell->insertAtTheEnd(tmp,tmp+3);
11632 int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11633 InternalAddPointOriented(e,-1,coords,tmp[1],tmp[2],*appendedCoords,tmp2);
11634 middles.push_back(tmp3+offset);
11637 middles.push_back(connBg[trueStart+nbOfEdges]);
11641 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)
11643 int tmpSrt(newConnOfCell->back()),tmpEnd(connBg[stp]);
11644 newConnOfCell->pushBackSilent(tmpEnd);
11649 int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11650 InternalAddPointOriented(e,-1,coords,tmpSrt,tmpEnd,*appendedCoords,tmp2);
11651 middles.push_back(tmp3+offset);
11654 middles.push_back(connBg[start+nbOfEdges]);
11658 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)
11660 // only the quadratic point to deal with:
11665 int tmpSrt(connBg[start]),tmpEnd(connBg[stp]);
11666 int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11667 InternalAddPointOriented(e,-1,coords,tmpSrt,tmpEnd,*appendedCoords,tmp2);
11668 middles.push_back(tmp3+offset);
11671 middles.push_back(connBg[start+nbOfEdges]);
11678 * 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 ) .
11679 * \a appendedCoords is a DataArrayDouble instance with number of components equal to one (even if the items are pushed by pair).
11681 bool MEDCouplingUMesh::Colinearize2DCell(const double *coords, const int *connBg, const int *connEnd, int offset, DataArrayInt *newConnOfCell, DataArrayDouble *appendedCoords)
11683 std::size_t sz(std::distance(connBg,connEnd));
11684 if(sz<3)//3 because 2+1(for the cell type) and 2 is the minimal number of edges of 2D cell.
11685 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Colinearize2DCell : the input cell has invalid format !");
11687 INTERP_KERNEL::AutoPtr<int> tmpConn(new int[sz]);
11688 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connBg[0]));
11689 unsigned nbs(cm.getNumberOfSons2(connBg+1,sz));
11690 unsigned nbOfHit(0); // number of fusions operated
11691 int posBaseElt(0),posEndElt(0),nbOfTurn(0);
11692 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
11693 INTERP_KERNEL::NormalizedCellType typeOfSon;
11694 std::vector<int> middles;
11696 for(;(nbOfTurn+nbOfHit)<nbs;nbOfTurn++)
11698 cm.fillSonCellNodalConnectivity2(posBaseElt,connBg+1,sz,tmpConn,typeOfSon);
11699 std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
11700 INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11701 posEndElt = posBaseElt+1;
11703 // Look backward first: are the final edges of the cells colinear with the first ones?
11704 // This initializes posBaseElt.
11707 for(unsigned i=1;i<nbs && nbOfHit<maxNbOfHit;i++) // 2nd condition is to avoid ending with a cell wih one single edge
11709 cm.fillSonCellNodalConnectivity2(nbs-i,connBg+1,sz,tmpConn,typeOfSon);
11710 INTERP_KERNEL::Edge *eCand(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11711 INTERP_KERNEL::EdgeIntersector *eint(INTERP_KERNEL::Edge::BuildIntersectorWith(e,eCand));
11712 bool isColinear=eint->areColinears();
11725 // Now move forward:
11726 const unsigned fwdStart = (nbOfTurn == 0 ? 0 : posBaseElt); // the first element to be inspected going forward
11727 for(unsigned j=fwdStart+1;j<nbs && nbOfHit<maxNbOfHit;j++) // 2nd condition is to avoid ending with a cell wih one single edge
11729 cm.fillSonCellNodalConnectivity2((int)j,connBg+1,sz,tmpConn,typeOfSon); // get edge #j's connectivity
11730 INTERP_KERNEL::Edge *eCand(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11731 INTERP_KERNEL::EdgeIntersector *eint(INTERP_KERNEL::Edge::BuildIntersectorWith(e,eCand));
11732 bool isColinear(eint->areColinears());
11744 //push [posBaseElt,posEndElt) in newConnOfCell using e
11745 // 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!
11747 // at the begining of the connectivity (insert type)
11748 EnterTheResultOf2DCellFirst(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
11749 else if((nbOfHit+nbOfTurn) != (nbs-1))
11751 EnterTheResultOf2DCellMiddle(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
11752 if ((nbOfHit+nbOfTurn) == (nbs-1))
11753 // at the end (only quad points to deal with)
11754 EnterTheResultOf2DCellEnd(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
11755 posBaseElt=posEndElt;
11758 if(!middles.empty())
11759 newConnOfCell->insertAtTheEnd(middles.begin(),middles.end());
11764 * It is the quadratic part of MEDCouplingUMesh::split2DCells. Here some additionnal nodes can be added at the end of coordinates array object.
11766 * \return int - the number of new nodes created.
11767 * \sa MEDCouplingUMesh::split2DCells
11769 int MEDCouplingUMesh::split2DCellsQuadratic(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *mid, const DataArrayInt *midI)
11771 checkConsistencyLight();
11772 int ncells(getNumberOfCells()),lgthToReach(getNodalConnectivityArrayLen()+2*subNodesInSeg->getNumberOfTuples()),nodesCnt(getNumberOfNodes());
11773 MCAuto<DataArrayInt> c(DataArrayInt::New()); c->alloc((std::size_t)lgthToReach);
11774 MCAuto<DataArrayDouble> addCoo(DataArrayDouble::New()); addCoo->alloc(0,1);
11775 const int *subPtr(subNodesInSeg->begin()),*subIPtr(subNodesInSegI->begin()),*descPtr(desc->begin()),*descIPtr(descI->begin()),*oldConn(getNodalConnectivity()->begin());
11776 const int *midPtr(mid->begin()),*midIPtr(midI->begin());
11777 const double *oldCoordsPtr(getCoords()->begin());
11778 int *cPtr(c->getPointer()),*ciPtr(getNodalConnectivityIndex()->getPointer());
11779 int prevPosOfCi(ciPtr[0]);
11780 for(int i=0;i<ncells;i++,ciPtr++,descIPtr++)
11782 int offset(descIPtr[0]),sz(descIPtr[1]-descIPtr[0]),deltaSz(sz);
11783 for(int j=0;j<sz;j++)
11784 { int sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]); deltaSz+=sz2; }
11785 *cPtr++=(int)INTERP_KERNEL::NORM_QPOLYG; cPtr[0]=oldConn[prevPosOfCi+1];
11786 for(int j=0;j<sz;j++)//loop over subedges of oldConn
11788 int offset2(subIPtr[descPtr[offset+j]]),sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]),offset3(midIPtr[descPtr[offset+j]]);
11792 cPtr[1]=oldConn[prevPosOfCi+2+j];
11793 cPtr[deltaSz]=oldConn[prevPosOfCi+1+j+sz]; cPtr++;
11796 std::vector<INTERP_KERNEL::Node *> ns(3);
11797 ns[0]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+j]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+j]+1]);
11798 ns[1]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+(1+j)%sz]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+(1+j)%sz]+1]);
11799 ns[2]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+sz+j]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+sz+j]+1]);
11800 MCAuto<INTERP_KERNEL::Edge> e(INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(ns));
11801 for(int k=0;k<sz2;k++)//loop over subsplit of current subedge
11803 cPtr[1]=subPtr[offset2+k];
11804 cPtr[deltaSz]=InternalAddPoint(e,midPtr[offset3+k],oldCoordsPtr,cPtr[0],cPtr[1],*addCoo,nodesCnt); cPtr++;
11806 int tmpEnd(oldConn[prevPosOfCi+1+(j+1)%sz]);
11808 { cPtr[1]=tmpEnd; }
11809 cPtr[deltaSz]=InternalAddPoint(e,midPtr[offset3+sz2],oldCoordsPtr,cPtr[0],tmpEnd,*addCoo,nodesCnt); cPtr++;
11811 prevPosOfCi=ciPtr[1]; cPtr+=deltaSz;
11812 ciPtr[1]=ciPtr[0]+1+2*deltaSz;//sz==old nb of nodes because (nb of subedges=nb of nodes for polygons)
11815 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCellsQuadratic : Some of edges to be split are orphan !");
11816 _nodal_connec->decrRef();
11817 _nodal_connec=c.retn(); _types.clear(); _types.insert(INTERP_KERNEL::NORM_QPOLYG);
11818 addCoo->rearrange(2);
11819 MCAuto<DataArrayDouble> coo(DataArrayDouble::Aggregate(getCoords(),addCoo));//info are copied from getCoords() by using Aggregate
11821 return addCoo->getNumberOfTuples();
11824 void MEDCouplingUMesh::ComputeAllTypesInternal(std::set<INTERP_KERNEL::NormalizedCellType>& types, const DataArrayInt *nodalConnec, const DataArrayInt *nodalConnecIndex)
11826 if(nodalConnec && nodalConnecIndex)
11829 const int *conn(nodalConnec->getConstPointer()),*connIndex(nodalConnecIndex->getConstPointer());
11830 int nbOfElem(nodalConnecIndex->getNbOfElems()-1);
11832 for(const int *pt=connIndex;pt!=connIndex+nbOfElem;pt++)
11833 types.insert((INTERP_KERNEL::NormalizedCellType)conn[*pt]);
11837 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
11838 _own_cell(true),_cell_id(-1),_nb_cell(0)
11843 _nb_cell=mesh->getNumberOfCells();
11847 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
11855 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_cell(itc),
11856 _own_cell(false),_cell_id(bg-1),
11863 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
11866 if(_cell_id<_nb_cell)
11875 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
11881 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
11883 return new MEDCouplingUMeshCellByTypeIterator(_mesh);
11886 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
11892 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh, INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_type(type),
11900 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
11906 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
11911 int MEDCouplingUMeshCellEntry::getNumberOfElems() const
11916 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
11918 return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
11921 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
11926 _nb_cell=mesh->getNumberOfCells();
11930 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
11937 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
11939 const int *c=_mesh->getNodalConnectivity()->getConstPointer();
11940 const int *ci=_mesh->getNodalConnectivityIndex()->getConstPointer();
11941 if(_cell_id<_nb_cell)
11943 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
11944 int nbOfElems=(int)std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type)));
11945 int startId=_cell_id;
11946 _cell_id+=nbOfElems;
11947 return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
11953 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
11957 _conn=mesh->getNodalConnectivity()->getPointer();
11958 _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
11962 void MEDCouplingUMeshCell::next()
11964 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
11969 _conn_lgth=_conn_indx[1]-_conn_indx[0];
11972 std::string MEDCouplingUMeshCell::repr() const
11974 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
11976 std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
11978 std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<int>(oss," "));
11982 return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
11985 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
11987 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
11988 return (INTERP_KERNEL::NormalizedCellType)_conn[0];
11990 return INTERP_KERNEL::NORM_ERROR;
11993 const int *MEDCouplingUMeshCell::getAllConn(int& lgth) const
11996 if(_conn_lgth!=NOTICABLE_FIRST_VAL)