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 * \warning Cells (and most notably polyhedrons) must be correctly oriented for this to work
1281 * properly. See orientCorrectlyPolyhedrons() and arePolyhedronsNotCorrectlyOriented().
1282 * \return \c true if at least one cell has been converted, \c false else. In the
1283 * last case the nodal connectivity remains unchanged.
1284 * \throw If the coordinates array is not set.
1285 * \throw If the nodal connectivity of cells is not defined.
1286 * \throw If \a this->getMeshDimension() < 0.
1288 bool MEDCouplingUMesh::unPolyze()
1290 checkFullyDefined();
1291 int mdim=getMeshDimension();
1293 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1296 int nbOfCells=getNumberOfCells();
1299 int initMeshLgth=getNodalConnectivityArrayLen();
1300 int *conn=_nodal_connec->getPointer();
1301 int *index=_nodal_connec_index->getPointer();
1306 for(int i=0;i<nbOfCells;i++)
1308 lgthOfCurCell=index[i+1]-posOfCurCell;
1309 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1310 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1311 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1315 switch(cm.getDimension())
1319 INTERP_KERNEL::AutoPtr<int> tmp=new int[lgthOfCurCell-1];
1320 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(int *)tmp);
1321 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1326 int nbOfFaces,lgthOfPolyhConn;
1327 INTERP_KERNEL::AutoPtr<int> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1328 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1333 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1337 ret=ret || (newType!=type);
1338 conn[newPos]=newType;
1340 posOfCurCell=index[i+1];
1345 std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1346 newPos+=lgthOfCurCell;
1347 posOfCurCell+=lgthOfCurCell;
1351 if(newPos!=initMeshLgth)
1352 _nodal_connec->reAlloc(newPos);
1359 * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1360 * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1361 * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells.
1363 * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not. This epsilon is used to recenter around origin to have maximal
1366 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1368 checkFullyDefined();
1369 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1370 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1371 MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1372 coords->recenterForMaxPrecision(eps);
1374 int nbOfCells=getNumberOfCells();
1375 const int *conn=_nodal_connec->getConstPointer();
1376 const int *index=_nodal_connec_index->getConstPointer();
1377 MCAuto<DataArrayInt> connINew=DataArrayInt::New();
1378 connINew->alloc(nbOfCells+1,1);
1379 int *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1380 MCAuto<DataArrayInt> connNew=DataArrayInt::New(); connNew->alloc(0,1);
1382 for(int i=0;i<nbOfCells;i++,connINewPtr++)
1384 if(conn[index[i]]==(int)INTERP_KERNEL::NORM_POLYHED)
1386 SimplifyPolyhedronCell(eps,coords,conn+index[i],conn+index[i+1],connNew);
1390 connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1391 *connINewPtr=connNew->getNumberOfTuples();
1394 setConnectivity(connNew,connINew,false);
1398 * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1399 * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1400 * the format of the returned DataArrayInt instance.
1402 * \return a newly allocated DataArrayInt sorted ascendingly of fetched node ids.
1403 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1405 DataArrayInt *MEDCouplingUMesh::computeFetchedNodeIds() const
1407 checkConnectivityFullyDefined();
1408 int nbOfCells=getNumberOfCells();
1409 const int *connIndex=_nodal_connec_index->getConstPointer();
1410 const int *conn=_nodal_connec->getConstPointer();
1411 const int *maxEltPt=std::max_element(_nodal_connec->begin(),_nodal_connec->end());
1412 int maxElt=maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1;
1413 std::vector<bool> retS(maxElt,false);
1414 for(int i=0;i<nbOfCells;i++)
1415 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1419 for(int i=0;i<maxElt;i++)
1422 DataArrayInt *ret=DataArrayInt::New();
1424 int *retPtr=ret->getPointer();
1425 for(int i=0;i<maxElt;i++)
1432 * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1433 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1435 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1437 int nbOfNodes((int)nodeIdsInUse.size()),nbOfCells(getNumberOfCells());
1438 const int *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1439 for(int i=0;i<nbOfCells;i++)
1440 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1443 if(conn[j]<nbOfNodes)
1444 nodeIdsInUse[conn[j]]=true;
1447 std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1448 throw INTERP_KERNEL::Exception(oss.str().c_str());
1454 * Finds nodes not used in any cell and returns an array giving a new id to every node
1455 * by excluding the unused nodes, for which the array holds -1. The result array is
1456 * a mapping in "Old to New" mode.
1457 * \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1458 * \return DataArrayInt * - a new instance of DataArrayInt. Its length is \a
1459 * this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1460 * if the node is unused or a new id else. The caller is to delete this
1461 * array using decrRef() as it is no more needed.
1462 * \throw If the coordinates array is not set.
1463 * \throw If the nodal connectivity of cells is not defined.
1464 * \throw If the nodal connectivity includes an invalid id.
1466 * \if ENABLE_EXAMPLES
1467 * \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1468 * \ref py_mcumesh_getNodeIdsInUse "Here is a Python example".
1470 * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1472 DataArrayInt *MEDCouplingUMesh::getNodeIdsInUse(int& nbrOfNodesInUse) const
1475 int nbOfNodes(getNumberOfNodes());
1476 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1477 ret->alloc(nbOfNodes,1);
1478 int *traducer=ret->getPointer();
1479 std::fill(traducer,traducer+nbOfNodes,-1);
1480 int nbOfCells=getNumberOfCells();
1481 const int *connIndex=_nodal_connec_index->getConstPointer();
1482 const int *conn=_nodal_connec->getConstPointer();
1483 for(int i=0;i<nbOfCells;i++)
1484 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1487 if(conn[j]<nbOfNodes)
1488 traducer[conn[j]]=1;
1491 std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1492 throw INTERP_KERNEL::Exception(oss.str().c_str());
1495 nbrOfNodesInUse=(int)std::count(traducer,traducer+nbOfNodes,1);
1496 std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1501 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1502 * For each cell in \b this the number of nodes constituting cell is computed.
1503 * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1504 * So for pohyhedrons some nodes can be counted several times in the returned result.
1506 * \return a newly allocated array
1507 * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1509 DataArrayInt *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1511 checkConnectivityFullyDefined();
1512 int nbOfCells=getNumberOfCells();
1513 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1514 ret->alloc(nbOfCells,1);
1515 int *retPtr=ret->getPointer();
1516 const int *conn=getNodalConnectivity()->getConstPointer();
1517 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1518 for(int i=0;i<nbOfCells;i++,retPtr++)
1520 if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1521 *retPtr=connI[i+1]-connI[i]-1;
1523 *retPtr=connI[i+1]-connI[i]-1-std::count(conn+connI[i]+1,conn+connI[i+1],-1);
1529 * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1530 * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1532 * \return DataArrayInt * - new object to be deallocated by the caller.
1533 * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1535 DataArrayInt *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1537 checkConnectivityFullyDefined();
1538 int nbOfCells=getNumberOfCells();
1539 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1540 ret->alloc(nbOfCells,1);
1541 int *retPtr=ret->getPointer();
1542 const int *conn=getNodalConnectivity()->getConstPointer();
1543 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1544 for(int i=0;i<nbOfCells;i++,retPtr++)
1546 std::set<int> s(conn+connI[i]+1,conn+connI[i+1]);
1547 if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1548 *retPtr=(int)s.size();
1552 *retPtr=(int)s.size();
1559 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1560 * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1562 * \return a newly allocated array
1564 DataArrayInt *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1566 checkConnectivityFullyDefined();
1567 int nbOfCells=getNumberOfCells();
1568 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1569 ret->alloc(nbOfCells,1);
1570 int *retPtr=ret->getPointer();
1571 const int *conn=getNodalConnectivity()->getConstPointer();
1572 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1573 for(int i=0;i<nbOfCells;i++,retPtr++,connI++)
1575 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1576 *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1582 * Removes unused nodes (the node coordinates array is shorten) and returns an array
1583 * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1584 * array mean that the corresponding old node is no more used.
1585 * \return DataArrayInt * - a new instance of DataArrayInt of length \a
1586 * this->getNumberOfNodes() before call of this method. The caller is to
1587 * delete this array using decrRef() as it is no more needed.
1588 * \throw If the coordinates array is not set.
1589 * \throw If the nodal connectivity of cells is not defined.
1590 * \throw If the nodal connectivity includes an invalid id.
1591 * \sa areAllNodesFetched
1593 * \if ENABLE_EXAMPLES
1594 * \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1595 * \ref py_mcumesh_zipCoordsTraducer "Here is a Python example".
1598 DataArrayInt *MEDCouplingUMesh::zipCoordsTraducer()
1600 return MEDCouplingPointSet::zipCoordsTraducer();
1604 * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1605 * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1607 int MEDCouplingUMesh::AreCellsEqual(const int *conn, const int *connI, int cell1, int cell2, int compType)
1612 return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1614 return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1616 return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1618 return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1620 return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1622 throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1626 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1628 int MEDCouplingUMesh::AreCellsEqualPolicy0(const int *conn, const int *connI, int cell1, int cell2)
1630 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1631 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1636 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1638 int MEDCouplingUMesh::AreCellsEqualPolicy1(const int *conn, const int *connI, int cell1, int cell2)
1640 int sz=connI[cell1+1]-connI[cell1];
1641 if(sz==connI[cell2+1]-connI[cell2])
1643 if(conn[connI[cell1]]==conn[connI[cell2]])
1645 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1646 unsigned dim=cm.getDimension();
1652 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1653 int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1654 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1655 work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1656 return work!=tmp+sz1?1:0;
1659 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1662 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1669 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1671 int MEDCouplingUMesh::AreCellsEqualPolicy2(const int *conn, const int *connI, int cell1, int cell2)
1673 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1675 if(conn[connI[cell1]]==conn[connI[cell2]])
1677 std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1678 std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1686 * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1688 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const int *conn, const int *connI, int cell1, int cell2)
1690 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1692 std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1693 std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1700 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1702 int MEDCouplingUMesh::AreCellsEqualPolicy7(const int *conn, const int *connI, int cell1, int cell2)
1704 int sz=connI[cell1+1]-connI[cell1];
1705 if(sz==connI[cell2+1]-connI[cell2])
1707 if(conn[connI[cell1]]==conn[connI[cell2]])
1709 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1710 unsigned dim=cm.getDimension();
1716 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1717 int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1718 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1719 work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1724 std::reverse_iterator<int *> it1((int *)tmp+sz1);
1725 std::reverse_iterator<int *> it2((int *)tmp);
1726 if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1732 return work!=tmp+sz1?1:0;
1735 {//case of SEG2 and SEG3
1736 if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1738 if(!cm.isQuadratic())
1740 std::reverse_iterator<const int *> it1(conn+connI[cell1+1]);
1741 std::reverse_iterator<const int *> it2(conn+connI[cell1]+1);
1742 if(std::equal(it1,it2,conn+connI[cell2]+1))
1748 if(conn[connI[cell1]+1]==conn[connI[cell2]+2] && conn[connI[cell1]+2]==conn[connI[cell2]+1] && conn[connI[cell1]+3]==conn[connI[cell2]+3])
1755 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1762 * This method find in candidate pool defined by 'candidates' the cells equal following the polycy 'compType'.
1763 * If any true is returned and the results will be put at the end of 'result' output parameter. If not false is returned
1764 * and result remains unchanged.
1765 * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1766 * If in 'candidates' pool -1 value is considered as an empty value.
1767 * WARNING this method returns only ONE set of result !
1769 bool MEDCouplingUMesh::AreCellsEqualInPool(const std::vector<int>& candidates, int compType, const int *conn, const int *connI, DataArrayInt *result)
1771 if(candidates.size()<1)
1774 std::vector<int>::const_iterator iter=candidates.begin();
1775 int start=(*iter++);
1776 for(;iter!=candidates.end();iter++)
1778 int status=AreCellsEqual(conn,connI,start,*iter,compType);
1783 result->pushBackSilent(start);
1787 result->pushBackSilent(*iter);
1789 result->pushBackSilent(status==2?(*iter+1):-(*iter+1));
1796 * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified
1798 * This method keeps the coordiantes of \a this. This method is time consuming.
1800 * \param [in] compType input specifying the technique used to compare cells each other.
1801 * - 0 : exactly. A cell is detected to be the same if and only if the connectivity is exactly the same without permutation and types same too. This is the strongest policy.
1802 * - 1 : permutation same orientation. cell1 and cell2 are considered equal if the connectivity of cell2 can be deduced by those of cell1 by direct permutation (with exactly the same orientation)
1803 * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1804 * - 2 : nodal. cell1 and cell2 are equal if and only if cell1 and cell2 have same type and have the same nodes constituting connectivity. This is the laziest policy. This policy
1805 * can be used for users not sensitive to orientation of cell
1806 * \param [in] startCellId specifies the cellId starting from which the equality computation will be carried out. By default it is 0, which it means that all cells in \a this will be scanned.
1807 * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1808 * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1809 * \return the correspondance array old to new in a newly allocated array.
1812 void MEDCouplingUMesh::findCommonCells(int compType, int startCellId, DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr) const
1814 MCAuto<DataArrayInt> revNodal=DataArrayInt::New(),revNodalI=DataArrayInt::New();
1815 getReverseNodalConnectivity(revNodal,revNodalI);
1816 FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1819 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, int startCellId, const DataArrayInt *nodal, const DataArrayInt *nodalI, const DataArrayInt *revNodal, const DataArrayInt *revNodalI,
1820 DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr)
1822 MCAuto<DataArrayInt> commonCells=DataArrayInt::New(),commonCellsI=DataArrayInt::New(); commonCells->alloc(0,1);
1823 int nbOfCells=nodalI->getNumberOfTuples()-1;
1824 commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1825 const int *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1826 const int *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1827 std::vector<bool> isFetched(nbOfCells,false);
1830 for(int i=0;i<nbOfCells;i++)
1834 const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1835 std::vector<int> v,v2;
1836 if(connOfNode!=connPtr+connIPtr[i+1])
1838 const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1839 v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1842 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1846 const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1847 std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1848 v2.resize(std::distance(v2.begin(),it));
1852 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1854 int pos=commonCellsI->back();
1855 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1856 for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1857 isFetched[*it]=true;
1865 for(int i=startCellId;i<nbOfCells;i++)
1869 const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1870 std::vector<int> v,v2;
1871 if(connOfNode!=connPtr+connIPtr[i+1])
1873 v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1876 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1880 std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1881 v2.resize(std::distance(v2.begin(),it));
1885 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1887 int pos=commonCellsI->back();
1888 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1889 for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1890 isFetched[*it]=true;
1896 commonCellsArr=commonCells.retn();
1897 commonCellsIArr=commonCellsI.retn();
1901 * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1902 * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1903 * than \a this->getNumberOfCells() in the returned array means that there is no
1904 * corresponding cell in \a this mesh.
1905 * It is expected that \a this and \a other meshes share the same node coordinates
1906 * array, if it is not so an exception is thrown.
1907 * \param [in] other - the mesh to compare with.
1908 * \param [in] compType - specifies a cell comparison technique. For meaning of its
1909 * valid values [0,1,2], see zipConnectivityTraducer().
1910 * \param [out] arr - a new instance of DataArrayInt returning correspondence
1911 * between cells of the two meshes. It contains \a other->getNumberOfCells()
1912 * values. The caller is to delete this array using
1913 * decrRef() as it is no more needed.
1914 * \return bool - \c true if all cells of \a other mesh are present in the \a this
1917 * \if ENABLE_EXAMPLES
1918 * \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1919 * \ref py_mcumesh_areCellsIncludedIn "Here is a Python example".
1921 * \sa checkDeepEquivalOnSameNodesWith()
1922 * \sa checkGeoEquivalWith()
1924 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayInt *& arr) const
1926 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1927 int nbOfCells=getNumberOfCells();
1928 static const int possibleCompType[]={0,1,2};
1929 if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1931 std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1932 std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1934 throw INTERP_KERNEL::Exception(oss.str().c_str());
1936 MCAuto<DataArrayInt> o2n=mesh->zipConnectivityTraducer(compType,nbOfCells);
1937 arr=o2n->subArray(nbOfCells);
1938 arr->setName(other->getName());
1940 if(other->getNumberOfCells()==0)
1942 return arr->getMaxValue(tmp)<nbOfCells;
1946 * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1947 * This method tries to determine if \b other is fully included in \b this.
1948 * The main difference is that this method is not expected to throw exception.
1949 * This method has two outputs :
1951 * \param other other mesh
1952 * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1953 * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
1955 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayInt *& arr) const
1957 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1958 DataArrayInt *commonCells=0,*commonCellsI=0;
1959 int thisNbCells=getNumberOfCells();
1960 mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
1961 MCAuto<DataArrayInt> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1962 const int *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
1963 int otherNbCells=other->getNumberOfCells();
1964 MCAuto<DataArrayInt> arr2=DataArrayInt::New();
1965 arr2->alloc(otherNbCells,1);
1966 arr2->fillWithZero();
1967 int *arr2Ptr=arr2->getPointer();
1968 int nbOfCommon=commonCellsI->getNumberOfTuples()-1;
1969 for(int i=0;i<nbOfCommon;i++)
1971 int start=commonCellsPtr[commonCellsIPtr[i]];
1972 if(start<thisNbCells)
1974 for(int j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
1976 int sig=commonCellsPtr[j]>0?1:-1;
1977 int val=std::abs(commonCellsPtr[j])-1;
1978 if(val>=thisNbCells)
1979 arr2Ptr[val-thisNbCells]=sig*(start+1);
1983 arr2->setName(other->getName());
1984 if(arr2->presenceOfValue(0))
1990 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
1993 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
1994 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
1996 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
1997 std::vector<const MEDCouplingUMesh *> ms(2);
2000 return MergeUMeshesOnSameCoords(ms);
2004 * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
2005 * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
2006 * cellIds is not given explicitely but by a range python like.
2011 * \param keepCoords that specifies if you want or not to keep coords as this or zip it (see MEDCoupling::MEDCouplingUMesh::zipCoords). If true zipCoords is \b NOT called, if false, zipCoords is called.
2012 * \return a newly allocated
2014 * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
2015 * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
2017 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(int start, int end, int step, bool keepCoords) const
2019 if(getMeshDimension()!=-1)
2020 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
2023 int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
2025 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2027 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2029 return const_cast<MEDCouplingUMesh *>(this);
2034 * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
2035 * The result mesh shares or not the node coordinates array with \a this mesh depending
2036 * on \a keepCoords parameter.
2037 * \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
2038 * to write this mesh to the MED file, its cells must be sorted using
2039 * sortCellsInMEDFileFrmt().
2040 * \param [in] begin - an array of cell ids to include to the new mesh.
2041 * \param [in] end - a pointer to last-plus-one-th element of \a begin.
2042 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2043 * array of \a this mesh, else "free" nodes are removed from the result mesh
2044 * by calling zipCoords().
2045 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2046 * to delete this mesh using decrRef() as it is no more needed.
2047 * \throw If the coordinates array is not set.
2048 * \throw If the nodal connectivity of cells is not defined.
2049 * \throw If any cell id in the array \a begin is not valid.
2051 * \if ENABLE_EXAMPLES
2052 * \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
2053 * \ref py_mcumesh_buildPartOfMySelf "Here is a Python example".
2056 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const int *begin, const int *end, bool keepCoords) const
2058 if(getMeshDimension()!=-1)
2059 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
2063 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2065 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2067 return const_cast<MEDCouplingUMesh *>(this);
2072 * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
2074 * This method allows to partially modify some cells in \b this (whose list is specified by [ \b cellIdsBg, \b cellIdsEnd ) ) with cells coming in \b otherOnSameCoordsThanThis.
2075 * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
2076 * The number of cells of \b this will remain the same with this method.
2078 * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
2079 * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
2080 * \param [in] otherOnSameCoordsThanThis an another mesh with same meshdimension than \b this with exactly the same number of cells than cell ids list in [\b cellIdsBg, \b cellIdsEnd ).
2081 * Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
2083 void MEDCouplingUMesh::setPartOfMySelf(const int *cellIdsBg, const int *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2085 checkConnectivityFullyDefined();
2086 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2087 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2088 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2089 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2091 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2092 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2093 throw INTERP_KERNEL::Exception(oss.str().c_str());
2095 int nbOfCellsToModify=(int)std::distance(cellIdsBg,cellIdsEnd);
2096 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2098 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2099 throw INTERP_KERNEL::Exception(oss.str().c_str());
2101 int nbOfCells=getNumberOfCells();
2102 bool easyAssign=true;
2103 const int *connI=_nodal_connec_index->getConstPointer();
2104 const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2105 for(const int *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2107 if(*it>=0 && *it<nbOfCells)
2109 easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2113 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2114 throw INTERP_KERNEL::Exception(oss.str().c_str());
2119 MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2124 DataArrayInt *arrOut=0,*arrIOut=0;
2125 MEDCouplingUMesh::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2127 MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2128 setConnectivity(arrOut,arrIOut,true);
2132 void MEDCouplingUMesh::setPartOfMySelfSlice(int start, int end, int step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2134 checkConnectivityFullyDefined();
2135 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2136 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2137 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2138 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2140 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2141 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2142 throw INTERP_KERNEL::Exception(oss.str().c_str());
2144 int nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2145 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2147 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2148 throw INTERP_KERNEL::Exception(oss.str().c_str());
2150 int nbOfCells=getNumberOfCells();
2151 bool easyAssign=true;
2152 const int *connI=_nodal_connec_index->getConstPointer();
2153 const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2155 for(int i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2157 if(it>=0 && it<nbOfCells)
2159 easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2163 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2164 throw INTERP_KERNEL::Exception(oss.str().c_str());
2169 MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2174 DataArrayInt *arrOut=0,*arrIOut=0;
2175 MEDCouplingUMesh::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2177 MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2178 setConnectivity(arrOut,arrIOut,true);
2183 * Keeps from \a this only cells which constituing point id are in the ids specified by [ \a begin,\a end ).
2184 * The resulting cell ids are stored at the end of the 'cellIdsKept' parameter.
2185 * Parameter \a fullyIn specifies if a cell that has part of its nodes in ids array is kept or not.
2186 * If \a fullyIn is true only cells whose ids are \b fully contained in [ \a begin,\a end ) tab will be kept.
2188 * \param [in] begin input start of array of node ids.
2189 * \param [in] end input end of array of node ids.
2190 * \param [in] fullyIn input that specifies if all node ids must be in [ \a begin,\a end ) array to consider cell to be in.
2191 * \param [in,out] cellIdsKeptArr array where all candidate cell ids are put at the end.
2193 void MEDCouplingUMesh::fillCellIdsToKeepFromNodeIds(const int *begin, const int *end, bool fullyIn, DataArrayInt *&cellIdsKeptArr) const
2195 MCAuto<DataArrayInt> cellIdsKept=DataArrayInt::New(); cellIdsKept->alloc(0,1);
2196 checkConnectivityFullyDefined();
2198 int sz=getNodalConnectivity()->getMaxValue(tmp); sz=std::max(sz,0)+1;
2199 std::vector<bool> fastFinder(sz,false);
2200 for(const int *work=begin;work!=end;work++)
2201 if(*work>=0 && *work<sz)
2202 fastFinder[*work]=true;
2203 int nbOfCells=getNumberOfCells();
2204 const int *conn=getNodalConnectivity()->getConstPointer();
2205 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2206 for(int i=0;i<nbOfCells;i++)
2208 int ref=0,nbOfHit=0;
2209 for(const int *work2=conn+connIndex[i]+1;work2!=conn+connIndex[i+1];work2++)
2213 if(fastFinder[*work2])
2216 if((ref==nbOfHit && fullyIn) || (nbOfHit!=0 && !fullyIn))
2217 cellIdsKept->pushBackSilent(i);
2219 cellIdsKeptArr=cellIdsKept.retn();
2223 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2224 * this->getMeshDimension(), that bound some cells of \a this mesh.
2225 * The cells of lower dimension to include to the result mesh are selected basing on
2226 * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2227 * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2228 * ==\c false, a cell is copied if any its node is in the array of node ids. The
2229 * created mesh shares the node coordinates array with \a this mesh.
2230 * \param [in] begin - the array of node ids.
2231 * \param [in] end - a pointer to the (last+1)-th element of \a begin.
2232 * \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2233 * array \a begin are added, else cells whose any node is in the
2234 * array \a begin are added.
2235 * \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2236 * to delete this mesh using decrRef() as it is no more needed.
2237 * \throw If the coordinates array is not set.
2238 * \throw If the nodal connectivity of cells is not defined.
2239 * \throw If any node id in \a begin is not valid.
2241 * \if ENABLE_EXAMPLES
2242 * \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2243 * \ref py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2246 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const int *begin, const int *end, bool fullyIn) const
2248 MCAuto<DataArrayInt> desc,descIndx,revDesc,revDescIndx;
2249 desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=DataArrayInt::New(); revDescIndx=DataArrayInt::New();
2250 MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2251 desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2252 return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2256 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2257 * this->getMeshDimension(), which bound only one cell of \a this mesh.
2258 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2259 * array of \a this mesh, else "free" nodes are removed from the result mesh
2260 * by calling zipCoords().
2261 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2262 * to delete this mesh using decrRef() as it is no more needed.
2263 * \throw If the coordinates array is not set.
2264 * \throw If the nodal connectivity of cells is not defined.
2266 * \if ENABLE_EXAMPLES
2267 * \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2268 * \ref py_mcumesh_buildBoundaryMesh "Here is a Python example".
2271 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2273 DataArrayInt *desc=DataArrayInt::New();
2274 DataArrayInt *descIndx=DataArrayInt::New();
2275 DataArrayInt *revDesc=DataArrayInt::New();
2276 DataArrayInt *revDescIndx=DataArrayInt::New();
2278 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2281 descIndx->decrRef();
2282 int nbOfCells=meshDM1->getNumberOfCells();
2283 const int *revDescIndxC=revDescIndx->getConstPointer();
2284 std::vector<int> boundaryCells;
2285 for(int i=0;i<nbOfCells;i++)
2286 if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2287 boundaryCells.push_back(i);
2288 revDescIndx->decrRef();
2289 MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2294 * This method returns a newly created DataArrayInt instance containing ids of cells located in boundary.
2295 * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2296 * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2298 DataArrayInt *MEDCouplingUMesh::findCellIdsOnBoundary() const
2300 checkFullyDefined();
2301 MCAuto<DataArrayInt> desc=DataArrayInt::New();
2302 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2303 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2304 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2306 buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2307 desc=(DataArrayInt*)0; descIndx=(DataArrayInt*)0;
2309 MCAuto<DataArrayInt> tmp=revDescIndx->deltaShiftIndex();
2310 MCAuto<DataArrayInt> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayInt*)0;
2311 const int *revDescPtr=revDesc->getConstPointer();
2312 const int *revDescIndxPtr=revDescIndx->getConstPointer();
2313 int nbOfCells=getNumberOfCells();
2314 std::vector<bool> ret1(nbOfCells,false);
2316 for(const int *pt=faceIds->begin();pt!=faceIds->end();pt++)
2317 if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2318 { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2320 DataArrayInt *ret2=DataArrayInt::New();
2322 int *ret2Ptr=ret2->getPointer();
2324 for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2327 ret2->setName("BoundaryCells");
2332 * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2333 * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2334 * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2335 * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2337 * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2338 * This method also returns the cells ids set s1 which contains the cell ids in \b this for which one of the dim-1 constituent
2339 * equals a cell in \b otherDimM1OnSameCoords.
2341 * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2342 * are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2344 * \param [in] otherDimM1OnSameCoords
2345 * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2346 * \param [out] cellIdsRk1 a newly allocated array containing the cell ids of s1 \b indexed into the \b cellIdsRk0 subset. To get the absolute ids of s1, simply invoke
2347 * cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2349 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *&cellIdsRk0, DataArrayInt *&cellIdsRk1) const
2351 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2352 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2353 checkConnectivityFullyDefined();
2354 otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2355 if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2356 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2357 MCAuto<DataArrayInt> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2358 MCAuto<DataArrayInt> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2359 MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2360 MCAuto<DataArrayInt> descThisPart=DataArrayInt::New(),descIThisPart=DataArrayInt::New(),revDescThisPart=DataArrayInt::New(),revDescIThisPart=DataArrayInt::New();
2361 MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2362 const int *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2363 DataArrayInt *idsOtherInConsti=0;
2364 bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2365 MCAuto<DataArrayInt> idsOtherInConstiAuto(idsOtherInConsti);
2367 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2369 for(const int *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2370 s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2371 MCAuto<DataArrayInt> s1arr_renum1=DataArrayInt::New(); s1arr_renum1->alloc((int)s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2372 s1arr_renum1->sort();
2373 cellIdsRk0=s0arr.retn();
2374 //cellIdsRk1=s_renum1.retn();
2375 cellIdsRk1=s1arr_renum1.retn();
2379 * This method computes the skin of \b this. That is to say the consituting meshdim-1 mesh is built and only the boundary subpart is
2380 * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2382 * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2384 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2386 MCAuto<DataArrayInt> desc=DataArrayInt::New();
2387 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2388 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2389 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2391 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2392 revDesc=0; desc=0; descIndx=0;
2393 MCAuto<DataArrayInt> revDescIndx2=revDescIndx->deltaShiftIndex();
2394 MCAuto<DataArrayInt> part=revDescIndx2->findIdsEqual(1);
2395 return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2399 * Finds nodes lying on the boundary of \a this mesh.
2400 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of found
2401 * nodes. The caller is to delete this array using decrRef() as it is no
2403 * \throw If the coordinates array is not set.
2404 * \throw If the nodal connectivity of cells is node defined.
2406 * \if ENABLE_EXAMPLES
2407 * \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2408 * \ref py_mcumesh_findBoundaryNodes "Here is a Python example".
2411 DataArrayInt *MEDCouplingUMesh::findBoundaryNodes() const
2413 MCAuto<MEDCouplingUMesh> skin=computeSkin();
2414 return skin->computeFetchedNodeIds();
2417 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2420 return const_cast<MEDCouplingUMesh *>(this);
2424 * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2425 * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2426 * This method searches for nodes needed to be duplicated. These nodes are nodes fetched by \b otherDimM1OnSameCoords which are not part of the boundary of \b otherDimM1OnSameCoords.
2427 * If a node is in the boundary of \b this \b and in the boundary of \b otherDimM1OnSameCoords this node is considerd as needed to be duplicated.
2428 * When the set of node ids \b nodeIdsToDuplicate is computed, cell ids in \b this is searched so that their connectivity includes at least 1 node in \b nodeIdsToDuplicate.
2430 * \param [in] otherDimM1OnSameCoords a mesh lying on the same coords than \b this and with a mesh dimension equal to those of \b this minus 1. WARNING this input
2431 * parameter is altered during the call.
2432 * \param [out] nodeIdsToDuplicate node ids needed to be duplicated following the algorithm explain above.
2433 * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2434 * \param [out] cellIdsNotModified cell ids int \b this that lies on \b otherDimM1OnSameCoords mesh whose connectivity do \b not need to be modified as it is the case for \b cellIdsNeededToBeRenum.
2436 * \warning This method modifies param \b otherDimM1OnSameCoords (for speed reasons).
2438 void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *& nodeIdsToDuplicate,
2439 DataArrayInt *& cellIdsNeededToBeRenum, DataArrayInt *& cellIdsNotModified) const
2441 typedef MCAuto<DataArrayInt> DAInt;
2442 typedef MCAuto<MEDCouplingUMesh> MCUMesh;
2444 checkFullyDefined();
2445 otherDimM1OnSameCoords.checkFullyDefined();
2446 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2447 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2448 if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2449 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2451 // Checking star-shaped M1 group:
2452 DAInt dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2453 MCUMesh meshM2 = otherDimM1OnSameCoords.buildDescendingConnectivity(dt0, dit0, rdt0, rdit0);
2454 DAInt dsi = rdit0->deltaShiftIndex();
2455 DAInt idsTmp0 = dsi->findIdsNotInRange(-1, 3);
2456 if(idsTmp0->getNumberOfTuples())
2457 throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2458 dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2460 // Get extreme nodes from the group (they won't be duplicated), ie nodes belonging to boundary cells of M1
2461 DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2462 MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2463 DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2464 // Remove from the list points on the boundary of the M0 mesh (those need duplication!)
2465 dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2466 MCUMesh m0desc = buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0;
2467 dsi = rdit0->deltaShiftIndex();
2468 DAInt boundSegs = dsi->findIdsEqual(1); // boundary segs/faces of the M0 mesh
2469 MCUMesh m0descSkin = static_cast<MEDCouplingUMesh *>(m0desc->buildPartOfMySelf(boundSegs->begin(),boundSegs->end(), true));
2470 DAInt fNodes = m0descSkin->computeFetchedNodeIds();
2471 // In 3D, some points on the boundary of M0 still need duplication:
2473 if (getMeshDimension() == 3)
2475 DAInt dnu1=DataArrayInt::New(), dnu2=DataArrayInt::New(), dnu3=DataArrayInt::New(), dnu4=DataArrayInt::New();
2476 MCUMesh m0descSkinDesc = m0descSkin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4);
2477 dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2478 DataArrayInt * corresp=0;
2479 meshM2->areCellsIncludedIn(m0descSkinDesc,2,corresp);
2480 DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2482 if (validIds->getNumberOfTuples())
2484 MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0descSkinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2485 DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2486 DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2487 notDup = xtrem->buildSubstraction(fNodes1);
2490 notDup = xtrem->buildSubstraction(fNodes);
2493 notDup = xtrem->buildSubstraction(fNodes);
2495 // Now compute cells around group (i.e. cells where we will do the propagation to identify the two sub-sets delimited by the group)
2496 DAInt m1Nodes = otherDimM1OnSameCoords.computeFetchedNodeIds();
2497 DAInt dupl = m1Nodes->buildSubstraction(notDup);
2498 DAInt cellsAroundGroup = getCellIdsLyingOnNodes(dupl->begin(), dupl->end(), false); // false= take cell in, even if not all nodes are in notDup
2501 MCUMesh m0Part2=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroup->begin(),cellsAroundGroup->end(),true));
2502 int nCells2 = m0Part2->getNumberOfCells();
2503 DAInt desc00=DataArrayInt::New(),descI00=DataArrayInt::New(),revDesc00=DataArrayInt::New(),revDescI00=DataArrayInt::New();
2504 MCUMesh m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00);
2506 // Neighbor information of the mesh without considering the crack (serves to count how many connex pieces it is made of)
2507 DataArrayInt *tmp00=0,*tmp11=0;
2508 MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00, tmp00, tmp11);
2509 DAInt neighInit00(tmp00);
2510 DAInt neighIInit00(tmp11);
2511 // Neighbor information of the mesh WITH the crack (some neighbors are removed):
2512 DataArrayInt *idsTmp=0;
2513 bool b=m01->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsTmp);
2515 // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2516 // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2517 MEDCouplingUMesh::RemoveIdsFromIndexedArrays(ids->begin(),ids->end(),desc00,descI00);
2518 DataArrayInt *tmp0=0,*tmp1=0;
2519 // Compute the neighbor of each cell in m0Part2, taking into account the broken link above. Two
2520 // cells on either side of the crack (defined by the mesh of low dimension) are not neighbor anymore.
2521 ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00,tmp0,tmp1);
2522 DAInt neigh00(tmp0);
2523 DAInt neighI00(tmp1);
2525 // For each initial connex part of the sub-mesh (or said differently for each independent crack):
2526 int seed = 0, nIter = 0;
2527 int nIterMax = nCells2+1; // Safety net for the loop
2528 DAInt hitCells = DataArrayInt::New(); hitCells->alloc(nCells2);
2529 hitCells->fillWithValue(-1);
2530 DAInt cellsToModifyConn0_torenum = DataArrayInt::New();
2531 cellsToModifyConn0_torenum->alloc(0,1);
2532 while (nIter < nIterMax)
2534 DAInt t = hitCells->findIdsEqual(-1);
2535 if (!t->getNumberOfTuples())
2537 // Connex zone without the crack (to compute the next seed really)
2539 DAInt connexCheck = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neighInit00,neighIInit00, -1, dnu);
2541 for (int * ptr = connexCheck->getPointer(); cnt < connexCheck->getNumberOfTuples(); ptr++, cnt++)
2542 hitCells->setIJ(*ptr,0,1);
2543 // Connex zone WITH the crack (to identify cells lying on either part of the crack)
2544 DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neigh00,neighI00, -1, dnu);
2545 cellsToModifyConn0_torenum = DataArrayInt::Aggregate(cellsToModifyConn0_torenum, spreadZone, 0);
2546 // Compute next seed, i.e. a cell in another connex part, which was not covered by the previous iterations
2547 DAInt comple = cellsToModifyConn0_torenum->buildComplement(nCells2);
2548 DAInt nonHitCells = hitCells->findIdsEqual(-1);
2549 DAInt intersec = nonHitCells->buildIntersection(comple);
2550 if (intersec->getNumberOfTuples())
2551 { seed = intersec->getIJ(0,0); }
2556 if (nIter >= nIterMax)
2557 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate(): internal error - too many iterations.");
2559 DAInt cellsToModifyConn1_torenum=cellsToModifyConn0_torenum->buildComplement(neighI00->getNumberOfTuples()-1);
2560 cellsToModifyConn0_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2561 cellsToModifyConn1_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2563 cellIdsNeededToBeRenum=cellsToModifyConn0_torenum.retn();
2564 cellIdsNotModified=cellsToModifyConn1_torenum.retn();
2565 nodeIdsToDuplicate=dupl.retn();
2569 * This method operates a modification of the connectivity and coords in \b this.
2570 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2571 * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2572 * 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
2573 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2574 * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2576 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2578 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2579 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2581 void MEDCouplingUMesh::duplicateNodes(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd)
2583 int nbOfNodes=getNumberOfNodes();
2584 duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2585 duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2589 * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2590 * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2592 * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2594 * \sa renumberNodesInConn
2596 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(int offset)
2598 checkConnectivityFullyDefined();
2599 int *conn(getNodalConnectivity()->getPointer());
2600 const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2601 int nbOfCells(getNumberOfCells());
2602 for(int i=0;i<nbOfCells;i++)
2603 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2605 int& node=conn[iconn];
2606 if(node>=0)//avoid polyhedron separator
2611 _nodal_connec->declareAsNew();
2616 * Same than renumberNodesInConn(const int *) except that here the format of old-to-new traducer is using map instead
2617 * 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
2620 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<int,int>& newNodeNumbersO2N)
2622 checkConnectivityFullyDefined();
2623 int *conn(getNodalConnectivity()->getPointer());
2624 const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2625 int nbOfCells(getNumberOfCells());
2626 for(int i=0;i<nbOfCells;i++)
2627 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2629 int& node=conn[iconn];
2630 if(node>=0)//avoid polyhedron separator
2632 INTERP_KERNEL::HashMap<int,int>::const_iterator it(newNodeNumbersO2N.find(node));
2633 if(it!=newNodeNumbersO2N.end())
2639 std::ostringstream oss; oss << "MEDCouplingUMesh::renumberNodesInConn(map) : presence in connectivity for cell #" << i << " of node #" << node << " : Not in map !";
2640 throw INTERP_KERNEL::Exception(oss.str().c_str());
2644 _nodal_connec->declareAsNew();
2649 * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2650 * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2651 * This method is a generalization of shiftNodeNumbersInConn().
2652 * \warning This method performs no check of validity of new ids. **Use it with care !**
2653 * \param [in] newNodeNumbersO2N - a permutation array, of length \a
2654 * this->getNumberOfNodes(), in "Old to New" mode.
2655 * See \ref numbering for more info on renumbering modes.
2656 * \throw If the nodal connectivity of cells is not defined.
2658 * \if ENABLE_EXAMPLES
2659 * \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2660 * \ref py_mcumesh_renumberNodesInConn "Here is a Python example".
2663 void MEDCouplingUMesh::renumberNodesInConn(const int *newNodeNumbersO2N)
2665 checkConnectivityFullyDefined();
2666 int *conn=getNodalConnectivity()->getPointer();
2667 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2668 int nbOfCells(getNumberOfCells());
2669 for(int i=0;i<nbOfCells;i++)
2670 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2672 int& node=conn[iconn];
2673 if(node>=0)//avoid polyhedron separator
2675 node=newNodeNumbersO2N[node];
2678 _nodal_connec->declareAsNew();
2683 * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2684 * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2685 * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2687 * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2689 void MEDCouplingUMesh::shiftNodeNumbersInConn(int delta)
2691 checkConnectivityFullyDefined();
2692 int *conn=getNodalConnectivity()->getPointer();
2693 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2694 int nbOfCells=getNumberOfCells();
2695 for(int i=0;i<nbOfCells;i++)
2696 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2698 int& node=conn[iconn];
2699 if(node>=0)//avoid polyhedron separator
2704 _nodal_connec->declareAsNew();
2709 * This method operates a modification of the connectivity in \b this.
2710 * 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.
2711 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2712 * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2713 * 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
2714 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2715 * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2717 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2718 * As an another consequense after the call of this method \b this can be transiently non cohrent.
2720 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2721 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2722 * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ).
2724 void MEDCouplingUMesh::duplicateNodesInConn(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd, int offset)
2726 checkConnectivityFullyDefined();
2727 std::map<int,int> m;
2729 for(const int *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2731 int *conn=getNodalConnectivity()->getPointer();
2732 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2733 int nbOfCells=getNumberOfCells();
2734 for(int i=0;i<nbOfCells;i++)
2735 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2737 int& node=conn[iconn];
2738 if(node>=0)//avoid polyhedron separator
2740 std::map<int,int>::iterator it=m.find(node);
2749 * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2751 * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2752 * After the call of this method the number of cells remains the same as before.
2754 * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2755 * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2756 * be strictly in [0;this->getNumberOfCells()).
2758 * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2759 * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2760 * should be contained in[0;this->getNumberOfCells()).
2762 * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2765 void MEDCouplingUMesh::renumberCells(const int *old2NewBg, bool check)
2767 checkConnectivityFullyDefined();
2768 int nbCells=getNumberOfCells();
2769 const int *array=old2NewBg;
2771 array=DataArrayInt::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2773 const int *conn=_nodal_connec->getConstPointer();
2774 const int *connI=_nodal_connec_index->getConstPointer();
2775 MCAuto<DataArrayInt> o2n=DataArrayInt::New(); o2n->useArray(array,false,C_DEALLOC,nbCells,1);
2776 MCAuto<DataArrayInt> n2o=o2n->invertArrayO2N2N2O(nbCells);
2777 const int *n2oPtr=n2o->begin();
2778 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
2779 newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2780 newConn->copyStringInfoFrom(*_nodal_connec);
2781 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
2782 newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2783 newConnI->copyStringInfoFrom(*_nodal_connec_index);
2785 int *newC=newConn->getPointer();
2786 int *newCI=newConnI->getPointer();
2789 for(int i=0;i<nbCells;i++)
2792 int nbOfElts=connI[pos+1]-connI[pos];
2793 newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2798 setConnectivity(newConn,newConnI);
2800 free(const_cast<int *>(array));
2804 * Finds cells whose bounding boxes intersect a given bounding box.
2805 * \param [in] bbox - an array defining the bounding box via coordinates of its
2806 * extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2808 * \param [in] eps - a factor used to increase size of the bounding box of cell
2809 * before comparing it with \a bbox. This factor is multiplied by the maximal
2810 * extent of the bounding box of cell to produce an addition to this bounding box.
2811 * \return DataArrayInt * - a new instance of DataArrayInt holding ids for found
2812 * cells. The caller is to delete this array using decrRef() as it is no more
2814 * \throw If the coordinates array is not set.
2815 * \throw If the nodal connectivity of cells is not defined.
2817 * \if ENABLE_EXAMPLES
2818 * \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2819 * \ref py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2822 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2824 MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2825 if(getMeshDimension()==-1)
2827 elems->pushBackSilent(0);
2828 return elems.retn();
2830 int dim=getSpaceDimension();
2831 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2832 const int* conn = getNodalConnectivity()->getConstPointer();
2833 const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2834 const double* coords = getCoords()->getConstPointer();
2835 int nbOfCells=getNumberOfCells();
2836 for ( int ielem=0; ielem<nbOfCells;ielem++ )
2838 for (int i=0; i<dim; i++)
2840 elem_bb[i*2]=std::numeric_limits<double>::max();
2841 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2844 for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2846 int node= conn[inode];
2847 if(node>=0)//avoid polyhedron separator
2849 for (int idim=0; idim<dim; idim++)
2851 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2853 elem_bb[idim*2] = coords[node*dim+idim] ;
2855 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2857 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2862 if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2863 elems->pushBackSilent(ielem);
2865 return elems.retn();
2869 * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2870 * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2871 * added in 'elems' parameter.
2873 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2875 MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2876 if(getMeshDimension()==-1)
2878 elems->pushBackSilent(0);
2879 return elems.retn();
2881 int dim=getSpaceDimension();
2882 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2883 const int* conn = getNodalConnectivity()->getConstPointer();
2884 const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2885 const double* coords = getCoords()->getConstPointer();
2886 int nbOfCells=getNumberOfCells();
2887 for ( int ielem=0; ielem<nbOfCells;ielem++ )
2889 for (int i=0; i<dim; i++)
2891 elem_bb[i*2]=std::numeric_limits<double>::max();
2892 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2895 for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2897 int node= conn[inode];
2898 if(node>=0)//avoid polyhedron separator
2900 for (int idim=0; idim<dim; idim++)
2902 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2904 elem_bb[idim*2] = coords[node*dim+idim] ;
2906 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2908 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2913 if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
2914 elems->pushBackSilent(ielem);
2916 return elems.retn();
2920 * Returns a type of a cell by its id.
2921 * \param [in] cellId - the id of the cell of interest.
2922 * \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
2923 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2925 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(int cellId) const
2927 const int *ptI=_nodal_connec_index->getConstPointer();
2928 const int *pt=_nodal_connec->getConstPointer();
2929 if(cellId>=0 && cellId<(int)_nodal_connec_index->getNbOfElems()-1)
2930 return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2933 std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2934 throw INTERP_KERNEL::Exception(oss.str().c_str());
2939 * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2940 * This method does not throw exception if geometric type \a type is not in \a this.
2941 * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2942 * The coordinates array is not considered here.
2944 * \param [in] type the geometric type
2945 * \return cell ids in this having geometric type \a type.
2947 DataArrayInt *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2950 MCAuto<DataArrayInt> ret=DataArrayInt::New();
2952 checkConnectivityFullyDefined();
2953 int nbCells=getNumberOfCells();
2954 int mdim=getMeshDimension();
2955 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
2956 if(mdim!=(int)cm.getDimension())
2957 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
2958 const int *ptI=_nodal_connec_index->getConstPointer();
2959 const int *pt=_nodal_connec->getConstPointer();
2960 for(int i=0;i<nbCells;i++)
2962 if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
2963 ret->pushBackSilent(i);
2969 * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
2971 int MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2973 const int *ptI=_nodal_connec_index->getConstPointer();
2974 const int *pt=_nodal_connec->getConstPointer();
2975 int nbOfCells=getNumberOfCells();
2977 for(int i=0;i<nbOfCells;i++)
2978 if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
2984 * Returns the nodal connectivity of a given cell.
2985 * The separator of faces within polyhedron connectivity (-1) is not returned, thus
2986 * all returned node ids can be used in getCoordinatesOfNode().
2987 * \param [in] cellId - an id of the cell of interest.
2988 * \param [in,out] conn - a vector where the node ids are appended. It is not
2989 * cleared before the appending.
2990 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2992 void MEDCouplingUMesh::getNodeIdsOfCell(int cellId, std::vector<int>& conn) const
2994 const int *ptI=_nodal_connec_index->getConstPointer();
2995 const int *pt=_nodal_connec->getConstPointer();
2996 for(const int *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
3001 std::string MEDCouplingUMesh::simpleRepr() const
3003 static const char msg0[]="No coordinates specified !";
3004 std::ostringstream ret;
3005 ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
3006 ret << "Description of mesh : \"" << getDescription() << "\"\n";
3008 double tt=getTime(tmpp1,tmpp2);
3009 ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
3010 ret << "Iteration : " << tmpp1 << " Order : " << tmpp2 << "\n";
3012 { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
3014 { ret << " Mesh dimension has not been set or is invalid !"; }
3017 const int spaceDim=getSpaceDimension();
3018 ret << spaceDim << "\nInfo attached on space dimension : ";
3019 for(int i=0;i<spaceDim;i++)
3020 ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
3024 ret << msg0 << "\n";
3025 ret << "Number of nodes : ";
3027 ret << getNumberOfNodes() << "\n";
3029 ret << msg0 << "\n";
3030 ret << "Number of cells : ";
3031 if(_nodal_connec!=0 && _nodal_connec_index!=0)
3032 ret << getNumberOfCells() << "\n";
3034 ret << "No connectivity specified !" << "\n";
3035 ret << "Cell types present : ";
3036 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
3038 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
3039 ret << cm.getRepr() << " ";
3045 std::string MEDCouplingUMesh::advancedRepr() const
3047 std::ostringstream ret;
3048 ret << simpleRepr();
3049 ret << "\nCoordinates array : \n___________________\n\n";
3051 _coords->reprWithoutNameStream(ret);
3053 ret << "No array set !\n";
3054 ret << "\n\nConnectivity arrays : \n_____________________\n\n";
3055 reprConnectivityOfThisLL(ret);
3060 * This method returns a C++ code that is a dump of \a this.
3061 * This method will throw if this is not fully defined.
3063 std::string MEDCouplingUMesh::cppRepr() const
3065 static const char coordsName[]="coords";
3066 static const char connName[]="conn";
3067 static const char connIName[]="connI";
3068 checkFullyDefined();
3069 std::ostringstream ret; ret << "// coordinates" << std::endl;
3070 _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
3071 _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
3072 _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
3073 ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
3074 ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
3075 ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
3076 ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
3080 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
3082 std::ostringstream ret;
3083 reprConnectivityOfThisLL(ret);
3088 * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsability to deal with.
3089 * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
3090 * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
3093 * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
3094 * 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
3095 * with number of tuples set to 0, if not the array is taken as this in the returned instance.
3097 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(int spaceDim) const
3099 int mdim=getMeshDimension();
3101 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
3102 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
3103 MCAuto<DataArrayInt> tmp1,tmp2;
3104 bool needToCpyCT=true;
3107 tmp1=DataArrayInt::New(); tmp1->alloc(0,1);
3115 if(!_nodal_connec_index)
3117 tmp2=DataArrayInt::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
3122 tmp2=_nodal_connec_index;
3125 ret->setConnectivity(tmp1,tmp2,false);
3130 MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
3131 ret->setCoords(coords);
3134 ret->setCoords(_coords);
3138 void MEDCouplingUMesh::reprConnectivityOfThisLL(std::ostringstream& stream) const
3140 if(_nodal_connec!=0 && _nodal_connec_index!=0)
3142 int nbOfCells=getNumberOfCells();
3143 const int *c=_nodal_connec->getConstPointer();
3144 const int *ci=_nodal_connec_index->getConstPointer();
3145 for(int i=0;i<nbOfCells;i++)
3147 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[i]]);
3148 stream << "Cell #" << i << " " << cm.getRepr() << " : ";
3149 std::copy(c+ci[i]+1,c+ci[i+1],std::ostream_iterator<int>(stream," "));
3154 stream << "Connectivity not defined !\n";
3157 int MEDCouplingUMesh::getNumberOfNodesInCell(int cellId) const
3159 const int *ptI=_nodal_connec_index->getConstPointer();
3160 const int *pt=_nodal_connec->getConstPointer();
3161 if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
3162 return ptI[cellId+1]-ptI[cellId]-1;
3164 return (int)std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind2nd(std::not_equal_to<int>(),-1));
3168 * Returns types of cells of the specified part of \a this mesh.
3169 * This method avoids computing sub-mesh explicitely to get its types.
3170 * \param [in] begin - an array of cell ids of interest.
3171 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3172 * \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3173 * describing the cell types.
3174 * \throw If the coordinates array is not set.
3175 * \throw If the nodal connectivity of cells is not defined.
3176 * \sa getAllGeoTypes()
3178 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const int *begin, const int *end) const
3180 checkFullyDefined();
3181 std::set<INTERP_KERNEL::NormalizedCellType> ret;
3182 const int *conn=_nodal_connec->getConstPointer();
3183 const int *connIndex=_nodal_connec_index->getConstPointer();
3184 for(const int *w=begin;w!=end;w++)
3185 ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3190 * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3191 * Optionally updates
3192 * a set of types of cells constituting \a this mesh.
3193 * This method is for advanced users having prepared their connectivity before. For
3194 * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3195 * \param [in] conn - the nodal connectivity array.
3196 * \param [in] connIndex - the nodal connectivity index array.
3197 * \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3200 void MEDCouplingUMesh::setConnectivity(DataArrayInt *conn, DataArrayInt *connIndex, bool isComputingTypes)
3202 DataArrayInt::SetArrayIn(conn,_nodal_connec);
3203 DataArrayInt::SetArrayIn(connIndex,_nodal_connec_index);
3204 if(isComputingTypes)
3210 * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3211 * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3213 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCopy):MEDCouplingPointSet(other,deepCopy),_mesh_dim(other._mesh_dim),
3214 _nodal_connec(0),_nodal_connec_index(0),
3215 _types(other._types)
3217 if(other._nodal_connec)
3218 _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCopy);
3219 if(other._nodal_connec_index)
3220 _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCopy);
3223 MEDCouplingUMesh::~MEDCouplingUMesh()
3226 _nodal_connec->decrRef();
3227 if(_nodal_connec_index)
3228 _nodal_connec_index->decrRef();
3232 * Recomputes a set of cell types of \a this mesh. For more info see
3233 * \ref MEDCouplingUMeshNodalConnectivity.
3235 void MEDCouplingUMesh::computeTypes()
3237 ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3241 * This method checks that all arrays are set. If yes nothing done if no an exception is thrown.
3243 void MEDCouplingUMesh::checkFullyDefined() const
3245 if(!_nodal_connec_index || !_nodal_connec || !_coords)
3246 throw INTERP_KERNEL::Exception("Reverse nodal connectivity computation requires full connectivity and coordinates set in unstructured mesh.");
3250 * This method checks that all connectivity arrays are set. If yes nothing done if no an exception is thrown.
3252 void MEDCouplingUMesh::checkConnectivityFullyDefined() const
3254 if(!_nodal_connec_index || !_nodal_connec)
3255 throw INTERP_KERNEL::Exception("Reverse nodal connectivity computation requires full connectivity set in unstructured mesh.");
3259 * Returns a number of cells constituting \a this mesh.
3260 * \return int - the number of cells in \a this mesh.
3261 * \throw If the nodal connectivity of cells is not defined.
3263 int MEDCouplingUMesh::getNumberOfCells() const
3265 if(_nodal_connec_index)
3266 return _nodal_connec_index->getNumberOfTuples()-1;
3271 throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3275 * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3276 * mesh. For more info see \ref meshes.
3277 * \return int - the dimension of \a this mesh.
3278 * \throw If the mesh dimension is not defined using setMeshDimension().
3280 int MEDCouplingUMesh::getMeshDimension() const
3283 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3288 * Returns a length of the nodal connectivity array.
3289 * This method is for test reason. Normally the integer returned is not useable by
3290 * user. For more info see \ref MEDCouplingUMeshNodalConnectivity.
3291 * \return int - the length of the nodal connectivity array.
3293 int MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3295 return _nodal_connec->getNbOfElems();
3299 * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3301 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<int>& tinyInfo, std::vector<std::string>& littleStrings) const
3303 MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3304 tinyInfo.push_back(getMeshDimension());
3305 tinyInfo.push_back(getNumberOfCells());
3307 tinyInfo.push_back(getNodalConnectivityArrayLen());
3309 tinyInfo.push_back(-1);
3313 * First step of unserialization process.
3315 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<int>& tinyInfo) const
3317 return tinyInfo[6]<=0;
3321 * Second step of serialization process.
3322 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3325 * \param littleStrings
3327 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<int>& tinyInfo, DataArrayInt *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3329 MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3331 a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3335 * Third and final step of serialization process.
3337 void MEDCouplingUMesh::serialize(DataArrayInt *&a1, DataArrayDouble *&a2) const
3339 MEDCouplingPointSet::serialize(a1,a2);
3340 if(getMeshDimension()>-1)
3342 a1=DataArrayInt::New();
3343 a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3344 int *ptA1=a1->getPointer();
3345 const int *conn=getNodalConnectivity()->getConstPointer();
3346 const int *index=getNodalConnectivityIndex()->getConstPointer();
3347 ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3348 std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3355 * Second and final unserialization process.
3356 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3358 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<int>& tinyInfo, const DataArrayInt *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3360 MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3361 setMeshDimension(tinyInfo[5]);
3365 const int *recvBuffer=a1->getConstPointer();
3366 MCAuto<DataArrayInt> myConnecIndex=DataArrayInt::New();
3367 myConnecIndex->alloc(tinyInfo[6]+1,1);
3368 std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3369 MCAuto<DataArrayInt> myConnec=DataArrayInt::New();
3370 myConnec->alloc(tinyInfo[7],1);
3371 std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3372 setConnectivity(myConnec, myConnecIndex);
3377 * This is the low algorithm of MEDCouplingUMesh::buildPartOfMySelfSlice.
3378 * CellIds are given using range specified by a start an end and step.
3380 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice(int start, int end, int step) const
3382 checkFullyDefined();
3383 int ncell=getNumberOfCells();
3384 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New();
3385 ret->_mesh_dim=_mesh_dim;
3386 ret->setCoords(_coords);
3387 int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice : ");
3388 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(newNbOfCells+1,1);
3389 int *newConnIPtr=newConnI->getPointer(); *newConnIPtr=0;
3391 const int *conn=_nodal_connec->getConstPointer();
3392 const int *connIndex=_nodal_connec_index->getConstPointer();
3393 for(int i=0;i<newNbOfCells;i++,newConnIPtr++,work+=step)
3395 if(work>=0 && work<ncell)
3397 newConnIPtr[1]=newConnIPtr[0]+connIndex[work+1]-connIndex[work];
3401 std::ostringstream oss; oss << "MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice : On pos #" << i << " input cell id =" << work << " should be in [0," << ncell << ") !";
3402 throw INTERP_KERNEL::Exception(oss.str().c_str());
3405 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(newConnIPtr[0],1);
3406 int *newConnPtr=newConn->getPointer();
3407 std::set<INTERP_KERNEL::NormalizedCellType> types;
3409 for(int i=0;i<newNbOfCells;i++,newConnIPtr++,work+=step)
3411 types.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[work]]);
3412 newConnPtr=std::copy(conn+connIndex[work],conn+connIndex[work+1],newConnPtr);
3414 ret->setConnectivity(newConn,newConnI,false);
3416 ret->copyTinyInfoFrom(this);
3421 * This is the low algorithm of MEDCouplingUMesh::buildPartOfMySelf.
3422 * Keeps from \a this only cells which constituing point id are in the ids specified by [ \a begin,\a end ).
3423 * The return newly allocated mesh will share the same coordinates as \a this.
3425 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfKeepCoords(const int *begin, const int *end) const
3427 checkConnectivityFullyDefined();
3428 int ncell=getNumberOfCells();
3429 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New();
3430 ret->_mesh_dim=_mesh_dim;
3431 ret->setCoords(_coords);
3432 std::size_t nbOfElemsRet=std::distance(begin,end);
3433 int *connIndexRet=(int *)malloc((nbOfElemsRet+1)*sizeof(int));
3435 const int *conn=_nodal_connec->getConstPointer();
3436 const int *connIndex=_nodal_connec_index->getConstPointer();
3438 for(const int *work=begin;work!=end;work++,newNbring++)
3440 if(*work>=0 && *work<ncell)
3441 connIndexRet[newNbring+1]=connIndexRet[newNbring]+connIndex[*work+1]-connIndex[*work];
3445 std::ostringstream oss; oss << "MEDCouplingUMesh::buildPartOfMySelfKeepCoords : On pos #" << std::distance(begin,work) << " input cell id =" << *work << " should be in [0," << ncell << ") !";
3446 throw INTERP_KERNEL::Exception(oss.str().c_str());
3449 int *connRet=(int *)malloc(connIndexRet[nbOfElemsRet]*sizeof(int));
3450 int *connRetWork=connRet;
3451 std::set<INTERP_KERNEL::NormalizedCellType> types;
3452 for(const int *work=begin;work!=end;work++)
3454 types.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*work]]);
3455 connRetWork=std::copy(conn+connIndex[*work],conn+connIndex[*work+1],connRetWork);
3457 MCAuto<DataArrayInt> connRetArr=DataArrayInt::New();
3458 connRetArr->useArray(connRet,true,C_DEALLOC,connIndexRet[nbOfElemsRet],1);
3459 MCAuto<DataArrayInt> connIndexRetArr=DataArrayInt::New();
3460 connIndexRetArr->useArray(connIndexRet,true,C_DEALLOC,(int)nbOfElemsRet+1,1);
3461 ret->setConnectivity(connRetArr,connIndexRetArr,false);
3463 ret->copyTinyInfoFrom(this);
3468 * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3470 * For 1D cells, the returned field contains lengths.<br>
3471 * For 2D cells, the returned field contains areas.<br>
3472 * For 3D cells, the returned field contains volumes.
3473 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3474 * orientation, i.e. the volume is always positive.
3475 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3476 * and one time . The caller is to delete this field using decrRef() as it is no
3479 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3481 std::string name="MeasureOfMesh_";
3483 int nbelem=getNumberOfCells();
3484 MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3485 field->setName(name);
3486 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3487 array->alloc(nbelem,1);
3488 double *area_vol=array->getPointer();
3489 field->setArray(array) ; array=0;
3490 field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3491 field->synchronizeTimeWithMesh();
3492 if(getMeshDimension()!=-1)
3495 INTERP_KERNEL::NormalizedCellType type;
3496 int dim_space=getSpaceDimension();
3497 const double *coords=getCoords()->getConstPointer();
3498 const int *connec=getNodalConnectivity()->getConstPointer();
3499 const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3500 for(int iel=0;iel<nbelem;iel++)
3502 ipt=connec_index[iel];
3503 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3504 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);
3507 std::transform(area_vol,area_vol+nbelem,area_vol,std::ptr_fun<double,double>(fabs));
3511 area_vol[0]=std::numeric_limits<double>::max();
3513 return field.retn();
3517 * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3519 * For 1D cells, the returned array contains lengths.<br>
3520 * For 2D cells, the returned array contains areas.<br>
3521 * For 3D cells, the returned array contains volumes.
3522 * This method avoids building explicitly a part of \a this mesh to perform the work.
3523 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3524 * orientation, i.e. the volume is always positive.
3525 * \param [in] begin - an array of cell ids of interest.
3526 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3527 * \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3528 * delete this array using decrRef() as it is no more needed.
3530 * \if ENABLE_EXAMPLES
3531 * \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3532 * \ref py_mcumesh_getPartMeasureField "Here is a Python example".
3534 * \sa getMeasureField()
3536 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const int *begin, const int *end) const
3538 std::string name="PartMeasureOfMesh_";
3540 int nbelem=(int)std::distance(begin,end);
3541 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3542 array->setName(name);
3543 array->alloc(nbelem,1);
3544 double *area_vol=array->getPointer();
3545 if(getMeshDimension()!=-1)
3548 INTERP_KERNEL::NormalizedCellType type;
3549 int dim_space=getSpaceDimension();
3550 const double *coords=getCoords()->getConstPointer();
3551 const int *connec=getNodalConnectivity()->getConstPointer();
3552 const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3553 for(const int *iel=begin;iel!=end;iel++)
3555 ipt=connec_index[*iel];
3556 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3557 *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<int,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3560 std::transform(array->getPointer(),area_vol,array->getPointer(),std::ptr_fun<double,double>(fabs));
3564 area_vol[0]=std::numeric_limits<double>::max();
3566 return array.retn();
3570 * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3571 * \a this one. The returned field contains the dual cell volume for each corresponding
3572 * node in \a this mesh. In other words, the field returns the getMeasureField() of
3573 * the dual mesh in P1 sens of \a this.<br>
3574 * For 1D cells, the returned field contains lengths.<br>
3575 * For 2D cells, the returned field contains areas.<br>
3576 * For 3D cells, the returned field contains volumes.
3577 * This method is useful to check "P1*" conservative interpolators.
3578 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3579 * orientation, i.e. the volume is always positive.
3580 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3581 * nodes and one time. The caller is to delete this array using decrRef() as
3582 * it is no more needed.
3584 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3586 MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3587 std::string name="MeasureOnNodeOfMesh_";
3589 int nbNodes=getNumberOfNodes();
3590 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3591 double cst=1./((double)getMeshDimension()+1.);
3592 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3593 array->alloc(nbNodes,1);
3594 double *valsToFill=array->getPointer();
3595 std::fill(valsToFill,valsToFill+nbNodes,0.);
3596 const double *values=tmp->getArray()->getConstPointer();
3597 MCAuto<DataArrayInt> da=DataArrayInt::New();
3598 MCAuto<DataArrayInt> daInd=DataArrayInt::New();
3599 getReverseNodalConnectivity(da,daInd);
3600 const int *daPtr=da->getConstPointer();
3601 const int *daIPtr=daInd->getConstPointer();
3602 for(int i=0;i<nbNodes;i++)
3603 for(const int *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3604 valsToFill[i]+=cst*values[*cell];
3606 ret->setArray(array);
3611 * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3612 * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3613 * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3614 * and are normalized.
3615 * <br> \a this can be either
3616 * - a 2D mesh in 2D or 3D space or
3617 * - an 1D mesh in 2D space.
3619 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3620 * cells and one time. The caller is to delete this field using decrRef() as
3621 * it is no more needed.
3622 * \throw If the nodal connectivity of cells is not defined.
3623 * \throw If the coordinates array is not set.
3624 * \throw If the mesh dimension is not set.
3625 * \throw If the mesh and space dimension is not as specified above.
3627 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3629 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3630 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3631 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3632 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3633 int nbOfCells=getNumberOfCells();
3634 int nbComp=getMeshDimension()+1;
3635 array->alloc(nbOfCells,nbComp);
3636 double *vals=array->getPointer();
3637 const int *connI=_nodal_connec_index->getConstPointer();
3638 const int *conn=_nodal_connec->getConstPointer();
3639 const double *coords=_coords->getConstPointer();
3640 if(getMeshDimension()==2)
3642 if(getSpaceDimension()==3)
3644 MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3645 const double *locPtr=loc->getConstPointer();
3646 for(int i=0;i<nbOfCells;i++,vals+=3)
3648 int offset=connI[i];
3649 INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3650 double n=INTERP_KERNEL::norm<3>(vals);
3651 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3656 MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3657 const double *isAbsPtr=isAbs->getArray()->begin();
3658 for(int i=0;i<nbOfCells;i++,isAbsPtr++)
3659 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3662 else//meshdimension==1
3665 for(int i=0;i<nbOfCells;i++)
3667 int offset=connI[i];
3668 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3669 double n=INTERP_KERNEL::norm<2>(tmp);
3670 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3675 ret->setArray(array);
3677 ret->synchronizeTimeWithSupport();
3682 * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3683 * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3684 * and are normalized.
3685 * <br> \a this can be either
3686 * - a 2D mesh in 2D or 3D space or
3687 * - an 1D mesh in 2D space.
3689 * This method avoids building explicitly a part of \a this mesh to perform the work.
3690 * \param [in] begin - an array of cell ids of interest.
3691 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3692 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3693 * cells and one time. The caller is to delete this field using decrRef() as
3694 * it is no more needed.
3695 * \throw If the nodal connectivity of cells is not defined.
3696 * \throw If the coordinates array is not set.
3697 * \throw If the mesh dimension is not set.
3698 * \throw If the mesh and space dimension is not as specified above.
3699 * \sa buildOrthogonalField()
3701 * \if ENABLE_EXAMPLES
3702 * \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3703 * \ref py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3706 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const int *begin, const int *end) const
3708 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3709 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3710 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3711 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3712 std::size_t nbelems=std::distance(begin,end);
3713 int nbComp=getMeshDimension()+1;
3714 array->alloc((int)nbelems,nbComp);
3715 double *vals=array->getPointer();
3716 const int *connI=_nodal_connec_index->getConstPointer();
3717 const int *conn=_nodal_connec->getConstPointer();
3718 const double *coords=_coords->getConstPointer();
3719 if(getMeshDimension()==2)
3721 if(getSpaceDimension()==3)
3723 MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3724 const double *locPtr=loc->getConstPointer();
3725 for(const int *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3727 int offset=connI[*i];
3728 INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3729 double n=INTERP_KERNEL::norm<3>(vals);
3730 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3735 for(std::size_t i=0;i<nbelems;i++)
3736 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3739 else//meshdimension==1
3742 for(const int *i=begin;i!=end;i++)
3744 int offset=connI[*i];
3745 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3746 double n=INTERP_KERNEL::norm<2>(tmp);
3747 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3752 ret->setArray(array);
3754 ret->synchronizeTimeWithSupport();
3759 * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3760 * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3761 * and are \b not normalized.
3762 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3763 * cells and one time. The caller is to delete this field using decrRef() as
3764 * it is no more needed.
3765 * \throw If the nodal connectivity of cells is not defined.
3766 * \throw If the coordinates array is not set.
3767 * \throw If \a this->getMeshDimension() != 1.
3768 * \throw If \a this mesh includes cells of type other than SEG2.
3770 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3772 if(getMeshDimension()!=1)
3773 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3774 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3775 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3776 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3777 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3778 int nbOfCells=getNumberOfCells();
3779 int spaceDim=getSpaceDimension();
3780 array->alloc(nbOfCells,spaceDim);
3781 double *pt=array->getPointer();
3782 const double *coo=getCoords()->getConstPointer();
3783 std::vector<int> conn;
3785 for(int i=0;i<nbOfCells;i++)
3788 getNodeIdsOfCell(i,conn);
3789 pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3791 ret->setArray(array);
3793 ret->synchronizeTimeWithSupport();
3798 * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3799 * returns a new DataArrayInt, of length equal to the number of 2D cells in the result
3800 * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3801 * from. If a result face is shared by two 3D cells, then the face in included twice in
3803 * \param [in] origin - 3 components of a point defining location of the plane.
3804 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3805 * must be greater than 1e-6.
3806 * \param [in] eps - half-thickness of the plane.
3807 * \param [out] cellIds - a new instance of DataArrayInt holding ids of 3D cells
3808 * producing correspondent 2D cells. The caller is to delete this array
3809 * using decrRef() as it is no more needed.
3810 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3811 * not share the node coordinates array with \a this mesh. The caller is to
3812 * delete this mesh using decrRef() as it is no more needed.
3813 * \throw If the coordinates array is not set.
3814 * \throw If the nodal connectivity of cells is not defined.
3815 * \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3816 * \throw If magnitude of \a vec is less than 1e-6.
3817 * \throw If the plane does not intersect any 3D cell of \a this mesh.
3818 * \throw If \a this includes quadratic cells.
3820 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3822 checkFullyDefined();
3823 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3824 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3825 MCAuto<DataArrayInt> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3826 if(candidates->empty())
3827 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3828 std::vector<int> nodes;
3829 DataArrayInt *cellIds1D=0;
3830 MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3831 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3832 MCAuto<DataArrayInt> desc1=DataArrayInt::New(),desc2=DataArrayInt::New();
3833 MCAuto<DataArrayInt> descIndx1=DataArrayInt::New(),descIndx2=DataArrayInt::New();
3834 MCAuto<DataArrayInt> revDesc1=DataArrayInt::New(),revDesc2=DataArrayInt::New();
3835 MCAuto<DataArrayInt> revDescIndx1=DataArrayInt::New(),revDescIndx2=DataArrayInt::New();
3836 MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3837 revDesc2=0; revDescIndx2=0;
3838 MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3839 revDesc1=0; revDescIndx1=0;
3840 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3841 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3843 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3844 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3846 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3847 std::vector< std::pair<int,int> > cut3DSurf(mDesc2->getNumberOfCells());
3848 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3849 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3850 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3851 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New());
3852 connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3853 subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3854 if(cellIds2->empty())
3855 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3856 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3857 ret->setCoords(mDesc1->getCoords());
3858 ret->setConnectivity(conn,connI,true);
3859 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3864 * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3865 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
3866 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3868 * \param [in] origin - 3 components of a point defining location of the plane.
3869 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3870 * must be greater than 1e-6.
3871 * \param [in] eps - half-thickness of the plane.
3872 * \param [out] cellIds - a new instance of DataArrayInt holding ids of faces
3873 * producing correspondent segments. The caller is to delete this array
3874 * using decrRef() as it is no more needed.
3875 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3876 * mesh in 3D space. This mesh does not share the node coordinates array with
3877 * \a this mesh. The caller is to delete this mesh using decrRef() as it is
3879 * \throw If the coordinates array is not set.
3880 * \throw If the nodal connectivity of cells is not defined.
3881 * \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3882 * \throw If magnitude of \a vec is less than 1e-6.
3883 * \throw If the plane does not intersect any 2D cell of \a this mesh.
3884 * \throw If \a this includes quadratic cells.
3886 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3888 checkFullyDefined();
3889 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3890 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3891 MCAuto<DataArrayInt> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3892 if(candidates->empty())
3893 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3894 std::vector<int> nodes;
3895 DataArrayInt *cellIds1D=0;
3896 MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3897 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3898 MCAuto<DataArrayInt> desc1=DataArrayInt::New();
3899 MCAuto<DataArrayInt> descIndx1=DataArrayInt::New();
3900 MCAuto<DataArrayInt> revDesc1=DataArrayInt::New();
3901 MCAuto<DataArrayInt> revDescIndx1=DataArrayInt::New();
3902 MCAuto<MEDCouplingUMesh> mDesc1=subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3903 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3904 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3906 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3907 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3909 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3910 int ncellsSub=subMesh->getNumberOfCells();
3911 std::vector< std::pair<int,int> > cut3DSurf(ncellsSub);
3912 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3913 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3914 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3915 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New()); connI->pushBackSilent(0);
3917 const int *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3918 const int *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3919 for(int i=0;i<ncellsSub;i++)
3921 if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3923 if(cut3DSurf[i].first!=-2)
3925 conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3926 connI->pushBackSilent(conn->getNumberOfTuples());
3927 cellIds2->pushBackSilent(i);
3931 int cellId3DSurf=cut3DSurf[i].second;
3932 int offset=nodalI[cellId3DSurf]+1;
3933 int nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3934 for(int j=0;j<nbOfEdges;j++)
3936 conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3937 connI->pushBackSilent(conn->getNumberOfTuples());
3938 cellIds2->pushBackSilent(cellId3DSurf);
3943 if(cellIds2->empty())
3944 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3945 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3946 ret->setCoords(mDesc1->getCoords());
3947 ret->setConnectivity(conn,connI,true);
3948 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3953 * Finds cells whose bounding boxes intersect a given plane.
3954 * \param [in] origin - 3 components of a point defining location of the plane.
3955 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3956 * must be greater than 1e-6.
3957 * \param [in] eps - half-thickness of the plane.
3958 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of the found
3959 * cells. The caller is to delete this array using decrRef() as it is no more
3961 * \throw If the coordinates array is not set.
3962 * \throw If the nodal connectivity of cells is not defined.
3963 * \throw If \a this->getSpaceDimension() != 3.
3964 * \throw If magnitude of \a vec is less than 1e-6.
3965 * \sa buildSlice3D()
3967 DataArrayInt *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
3969 checkFullyDefined();
3970 if(getSpaceDimension()!=3)
3971 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
3972 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
3974 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
3976 vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
3977 double angle=acos(vec[2]/normm);
3978 MCAuto<DataArrayInt> cellIds;
3982 MCAuto<DataArrayDouble> coo=_coords->deepCopy();
3983 double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
3984 if(normm2/normm>1e-6)
3985 MEDCouplingPointSet::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer());
3986 MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
3988 mw->getBoundingBox(bbox);
3989 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3990 cellIds=mw->getCellsInBoundingBox(bbox,eps);
3994 getBoundingBox(bbox);
3995 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3996 cellIds=getCellsInBoundingBox(bbox,eps);
3998 return cellIds.retn();
4002 * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
4003 * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
4004 * No consideration of coordinate is done by this method.
4005 * 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)
4006 * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be usefull.
4008 bool MEDCouplingUMesh::isContiguous1D() const
4010 if(getMeshDimension()!=1)
4011 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
4012 int nbCells=getNumberOfCells();
4014 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
4015 const int *connI=_nodal_connec_index->getConstPointer();
4016 const int *conn=_nodal_connec->getConstPointer();
4017 int ref=conn[connI[0]+2];
4018 for(int i=1;i<nbCells;i++)
4020 if(conn[connI[i]+1]!=ref)
4022 ref=conn[connI[i]+2];
4028 * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
4029 * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
4030 * \param pt reference point of the line
4031 * \param v normalized director vector of the line
4032 * \param eps max precision before throwing an exception
4033 * \param res output of size this->getNumberOfCells
4035 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
4037 if(getMeshDimension()!=1)
4038 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
4039 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
4040 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
4041 if(getSpaceDimension()!=3)
4042 throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
4043 MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
4044 const double *fPtr=f->getArray()->getConstPointer();
4046 for(int i=0;i<getNumberOfCells();i++)
4048 const double *tmp1=fPtr+3*i;
4049 tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
4050 tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
4051 tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
4052 double n1=INTERP_KERNEL::norm<3>(tmp);
4053 n1/=INTERP_KERNEL::norm<3>(tmp1);
4055 throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
4057 const double *coo=getCoords()->getConstPointer();
4058 for(int i=0;i<getNumberOfNodes();i++)
4060 std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
4061 std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
4062 res[i]=std::accumulate(tmp,tmp+3,0.);
4067 * 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.
4068 * \a this is expected to be a mesh so that its space dimension is equal to its
4069 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4070 * 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).
4072 * 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
4073 * 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).
4074 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4076 * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
4077 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4079 * \param [in] ptBg the start pointer (included) of the coordinates of the point
4080 * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
4081 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4082 * \return the positive value of the distance.
4083 * \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
4085 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
4087 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, int& cellId) const
4089 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4090 if(meshDim!=spaceDim-1)
4091 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
4092 if(meshDim!=2 && meshDim!=1)
4093 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
4094 checkFullyDefined();
4095 if((int)std::distance(ptBg,ptEnd)!=spaceDim)
4096 { 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()); }
4097 DataArrayInt *ret1=0;
4098 MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,C_DEALLOC,1,spaceDim);
4099 MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
4100 MCAuto<DataArrayInt> ret1Safe(ret1);
4101 cellId=*ret1Safe->begin();
4102 return *ret0->begin();
4106 * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
4107 * to \a this and the first \a cellId in \a this corresponding to the returned distance.
4108 * 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
4109 * 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).
4110 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4112 * \a this is expected to be a mesh so that its space dimension is equal to its
4113 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4114 * 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).
4116 * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
4117 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4119 * \param [in] pts the list of points in which each tuple represents a point
4120 * \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.
4121 * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
4122 * \throw if number of components of \a pts is not equal to the space dimension.
4123 * \throw if mesh dimension of \a this is not equal to space dimension - 1.
4124 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
4126 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayInt *& cellIds) const
4129 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
4130 pts->checkAllocated();
4131 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4132 if(meshDim!=spaceDim-1)
4133 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
4134 if(meshDim!=2 && meshDim!=1)
4135 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
4136 if(pts->getNumberOfComponents()!=spaceDim)
4138 std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
4139 throw INTERP_KERNEL::Exception(oss.str().c_str());
4141 checkFullyDefined();
4142 int nbCells=getNumberOfCells();
4144 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
4145 int nbOfPts=pts->getNumberOfTuples();
4146 MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
4147 MCAuto<DataArrayInt> ret1=DataArrayInt::New(); ret1->alloc(nbOfPts,1);
4148 const int *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
4149 double *ret0Ptr=ret0->getPointer(); int *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
4150 MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
4151 const double *bbox(bboxArr->begin());
4156 BBTreeDst<3> myTree(bbox,0,0,nbCells);
4157 for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
4159 double x=std::numeric_limits<double>::max();
4160 std::vector<int> elems;
4161 myTree.getMinDistanceOfMax(ptsPtr,x);
4162 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4163 DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4169 BBTreeDst<2> myTree(bbox,0,0,nbCells);
4170 for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4172 double x=std::numeric_limits<double>::max();
4173 std::vector<int> elems;
4174 myTree.getMinDistanceOfMax(ptsPtr,x);
4175 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4176 DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4181 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4183 cellIds=ret1.retn();
4190 * \param [in] pt the start pointer (included) of the coordinates of the point
4191 * \param [in] cellIdsBg the start pointer (included) of cellIds
4192 * \param [in] cellIdsEnd the end pointer (excluded) of cellIds
4193 * \param [in] nc nodal connectivity
4194 * \param [in] ncI nodal connectivity index
4195 * \param [in,out] ret0 the min distance between \a this and the external input point
4196 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4197 * \sa MEDCouplingUMesh::distanceToPoint, MEDCouplingUMesh::distanceToPoints
4199 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)
4202 ret0=std::numeric_limits<double>::max();
4203 for(const int *zeCell=cellIdsBg;zeCell!=cellIdsEnd;zeCell++)
4205 switch((INTERP_KERNEL::NormalizedCellType)nc[ncI[*zeCell]])
4207 case INTERP_KERNEL::NORM_TRI3:
4209 double tmp=INTERP_KERNEL::DistanceFromPtToTriInSpaceDim3(pt,coords+3*nc[ncI[*zeCell]+1],coords+3*nc[ncI[*zeCell]+2],coords+3*nc[ncI[*zeCell]+3]);
4211 { ret0=tmp; cellId=*zeCell; }
4214 case INTERP_KERNEL::NORM_QUAD4:
4215 case INTERP_KERNEL::NORM_POLYGON:
4217 double tmp=INTERP_KERNEL::DistanceFromPtToPolygonInSpaceDim3(pt,nc+ncI[*zeCell]+1,nc+ncI[*zeCell+1],coords);
4219 { ret0=tmp; cellId=*zeCell; }
4223 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint3DSurfAlg : not managed cell type ! Supporting TRI3, QUAD4 and POLYGON !");
4229 * \param [in] pt the start pointer (included) of the coordinates of the point
4230 * \param [in] cellIdsBg the start pointer (included) of cellIds
4231 * \param [in] cellIdsEnd the end pointer (excluded) of cellIds
4232 * \param [in] nc nodal connectivity
4233 * \param [in] ncI nodal connectivity index
4234 * \param [in,out] ret0 the min distance between \a this and the external input point
4235 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4236 * \sa MEDCouplingUMesh::distanceToPoint, MEDCouplingUMesh::distanceToPoints
4238 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)
4241 ret0=std::numeric_limits<double>::max();
4242 for(const int *zeCell=cellIdsBg;zeCell!=cellIdsEnd;zeCell++)
4244 switch((INTERP_KERNEL::NormalizedCellType)nc[ncI[*zeCell]])
4246 case INTERP_KERNEL::NORM_SEG2:
4248 std::size_t uselessEntry=0;
4249 double tmp=INTERP_KERNEL::SquareDistanceFromPtToSegInSpaceDim2(pt,coords+2*nc[ncI[*zeCell]+1],coords+2*nc[ncI[*zeCell]+2],uselessEntry);
4252 { ret0=tmp; cellId=*zeCell; }
4256 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint2DCurveAlg : not managed cell type ! Supporting SEG2 !");
4263 * Finds cells in contact with a ball (i.e. a point with precision).
4264 * 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.
4265 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4267 * \warning This method is suitable if the caller intends to evaluate only one
4268 * point, for more points getCellsContainingPoints() is recommended as it is
4270 * \param [in] pos - array of coordinates of the ball central point.
4271 * \param [in] eps - ball radius.
4272 * \return int - a smallest id of cells being in contact with the ball, -1 in case
4273 * if there are no such cells.
4274 * \throw If the coordinates array is not set.
4275 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4277 int MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4279 std::vector<int> elts;
4280 getCellsContainingPoint(pos,eps,elts);
4283 return elts.front();
4287 * Finds cells in contact with a ball (i.e. a point with precision).
4288 * 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.
4289 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4290 * \warning This method is suitable if the caller intends to evaluate only one
4291 * point, for more points getCellsContainingPoints() is recommended as it is
4293 * \param [in] pos - array of coordinates of the ball central point.
4294 * \param [in] eps - ball radius.
4295 * \param [out] elts - vector returning ids of the found cells. It is cleared
4296 * before inserting ids.
4297 * \throw If the coordinates array is not set.
4298 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4300 * \if ENABLE_EXAMPLES
4301 * \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4302 * \ref py_mcumesh_getCellsContainingPoint "Here is a Python example".
4305 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<int>& elts) const
4307 MCAuto<DataArrayInt> eltsUg,eltsIndexUg;
4308 getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4309 elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4314 namespace MEDCoupling
4316 template<const int SPACEDIMM>
4320 static const int MY_SPACEDIM=SPACEDIMM;
4321 static const int MY_MESHDIM=8;
4322 typedef int MyConnType;
4323 static const INTERP_KERNEL::NumberingPolicy My_numPol=INTERP_KERNEL::ALL_C_MODE;
4325 // useless, but for windows compilation ...
4326 const double* getCoordinatesPtr() const { return 0; }
4327 const int* getConnectivityPtr() const { return 0; }
4328 const int* getConnectivityIndexPtr() const { return 0; }
4329 INTERP_KERNEL::NormalizedCellType getTypeOfElement(int) const { return (INTERP_KERNEL::NormalizedCellType)0; }
4333 INTERP_KERNEL::Edge *MEDCouplingUMeshBuildQPFromEdge2(INTERP_KERNEL::NormalizedCellType typ, const int *bg, const double *coords2D, std::map< MCAuto<INTERP_KERNEL::Node>,int>& m)
4335 INTERP_KERNEL::Edge *ret(0);
4336 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]));
4337 m[n0]=bg[0]; m[n1]=bg[1];
4340 case INTERP_KERNEL::NORM_SEG2:
4342 ret=new INTERP_KERNEL::EdgeLin(n0,n1);
4345 case INTERP_KERNEL::NORM_SEG3:
4347 INTERP_KERNEL::Node *n2(new INTERP_KERNEL::Node(coords2D[2*bg[2]],coords2D[2*bg[2]+1])); m[n2]=bg[2];
4348 INTERP_KERNEL::EdgeLin *e1(new INTERP_KERNEL::EdgeLin(n0,n2)),*e2(new INTERP_KERNEL::EdgeLin(n2,n1));
4349 INTERP_KERNEL::SegSegIntersector inters(*e1,*e2);
4350 // is the SEG3 degenerated, and thus can be reduced to a SEG2?
4351 bool colinearity(inters.areColinears());
4352 delete e1; delete e2;
4354 { ret=new INTERP_KERNEL::EdgeLin(n0,n1); }
4356 { ret=new INTERP_KERNEL::EdgeArcCircle(n0,n2,n1); }
4360 throw INTERP_KERNEL::Exception("MEDCouplingUMeshBuildQPFromEdge2 : Expecting a mesh with spaceDim==2 and meshDim==1 !");
4365 INTERP_KERNEL::Edge *MEDCouplingUMeshBuildQPFromEdge(INTERP_KERNEL::NormalizedCellType typ, std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >& mapp2, const int *bg)
4367 INTERP_KERNEL::Edge *ret=0;
4370 case INTERP_KERNEL::NORM_SEG2:
4372 ret=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[1]].first);
4375 case INTERP_KERNEL::NORM_SEG3:
4377 INTERP_KERNEL::EdgeLin *e1=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[2]].first);
4378 INTERP_KERNEL::EdgeLin *e2=new INTERP_KERNEL::EdgeLin(mapp2[bg[2]].first,mapp2[bg[1]].first);
4379 INTERP_KERNEL::SegSegIntersector inters(*e1,*e2);
4380 // is the SEG3 degenerated, and thus can be reduced to a SEG2?
4381 bool colinearity=inters.areColinears();
4382 delete e1; delete e2;
4384 ret=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[1]].first);
4386 ret=new INTERP_KERNEL::EdgeArcCircle(mapp2[bg[0]].first,mapp2[bg[2]].first,mapp2[bg[1]].first);
4387 mapp2[bg[2]].second=false;
4391 throw INTERP_KERNEL::Exception("MEDCouplingUMeshBuildQPFromEdge : Expecting a mesh with spaceDim==2 and meshDim==1 !");
4397 * This method creates a sub mesh in Geometric2D DS. The sub mesh is composed by the sub set of cells in 'candidates' taken from
4398 * the global mesh 'mDesc'.
4399 * The input mesh 'mDesc' must be so that mDim==1 and spaceDim==2.
4400 * 'mapp' returns a mapping between local numbering in submesh (represented by a Node*) and the global node numbering in 'mDesc'.
4402 INTERP_KERNEL::QuadraticPolygon *MEDCouplingUMeshBuildQPFromMesh(const MEDCouplingUMesh *mDesc, const std::vector<int>& candidates,
4403 std::map<INTERP_KERNEL::Node *,int>& mapp)
4406 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.
4407 const double *coo=mDesc->getCoords()->getConstPointer();
4408 const int *c=mDesc->getNodalConnectivity()->getConstPointer();
4409 const int *cI=mDesc->getNodalConnectivityIndex()->getConstPointer();
4411 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
4412 s.insert(c+cI[*it]+1,c+cI[(*it)+1]);
4413 for(std::set<int>::const_iterator it2=s.begin();it2!=s.end();it2++)
4415 INTERP_KERNEL::Node *n=new INTERP_KERNEL::Node(coo[2*(*it2)],coo[2*(*it2)+1]);
4416 mapp2[*it2]=std::pair<INTERP_KERNEL::Node *,bool>(n,true);
4418 INTERP_KERNEL::QuadraticPolygon *ret=new INTERP_KERNEL::QuadraticPolygon;
4419 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
4421 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[*it]];
4422 ret->pushBack(MEDCouplingUMeshBuildQPFromEdge(typ,mapp2,c+cI[*it]+1));
4424 for(std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >::const_iterator it2=mapp2.begin();it2!=mapp2.end();it2++)
4426 if((*it2).second.second)
4427 mapp[(*it2).second.first]=(*it2).first;
4428 ((*it2).second.first)->decrRef();
4433 INTERP_KERNEL::Node *MEDCouplingUMeshBuildQPNode(int nodeId, const double *coo1, int offset1, const double *coo2, int offset2, const std::vector<double>& addCoo)
4437 int locId=nodeId-offset2;
4438 return new INTERP_KERNEL::Node(addCoo[2*locId],addCoo[2*locId+1]);
4442 int locId=nodeId-offset1;
4443 return new INTERP_KERNEL::Node(coo2[2*locId],coo2[2*locId+1]);
4445 return new INTERP_KERNEL::Node(coo1[2*nodeId],coo1[2*nodeId+1]);
4449 * Construct a mapping between set of Nodes and the standart MEDCoupling connectivity format (c, cI).
4451 void MEDCouplingUMeshBuildQPFromMesh3(const double *coo1, int offset1, const double *coo2, int offset2, const std::vector<double>& addCoo,
4452 const int *desc1Bg, const int *desc1End, const std::vector<std::vector<int> >& intesctEdges1,
4453 /*output*/std::map<INTERP_KERNEL::Node *,int>& mapp, std::map<int,INTERP_KERNEL::Node *>& mappRev)
4455 for(const int *desc1=desc1Bg;desc1!=desc1End;desc1++)
4457 int eltId1=abs(*desc1)-1;
4458 for(std::vector<int>::const_iterator it1=intesctEdges1[eltId1].begin();it1!=intesctEdges1[eltId1].end();it1++)
4460 std::map<int,INTERP_KERNEL::Node *>::const_iterator it=mappRev.find(*it1);
4461 if(it==mappRev.end())
4463 INTERP_KERNEL::Node *node=MEDCouplingUMeshBuildQPNode(*it1,coo1,offset1,coo2,offset2,addCoo);
4474 template<int SPACEDIM>
4475 void MEDCouplingUMesh::getCellsContainingPointsAlg(const double *coords, const double *pos, int nbOfPoints,
4476 double eps, MCAuto<DataArrayInt>& elts, MCAuto<DataArrayInt>& eltsIndex) const
4478 elts=DataArrayInt::New(); eltsIndex=DataArrayInt::New(); eltsIndex->alloc(nbOfPoints+1,1); eltsIndex->setIJ(0,0,0); elts->alloc(0,1);
4479 int *eltsIndexPtr(eltsIndex->getPointer());
4480 MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree(eps));
4481 const double *bbox(bboxArr->begin());
4482 int nbOfCells=getNumberOfCells();
4483 const int *conn=_nodal_connec->getConstPointer();
4484 const int *connI=_nodal_connec_index->getConstPointer();
4485 double bb[2*SPACEDIM];
4486 BBTree<SPACEDIM,int> myTree(&bbox[0],0,0,nbOfCells,-eps);
4487 for(int i=0;i<nbOfPoints;i++)
4489 eltsIndexPtr[i+1]=eltsIndexPtr[i];
4490 for(int j=0;j<SPACEDIM;j++)
4492 bb[2*j]=pos[SPACEDIM*i+j];
4493 bb[2*j+1]=pos[SPACEDIM*i+j];
4495 std::vector<int> candidates;
4496 myTree.getIntersectingElems(bb,candidates);
4497 for(std::vector<int>::const_iterator iter=candidates.begin();iter!=candidates.end();iter++)
4499 int sz(connI[(*iter)+1]-connI[*iter]-1);
4500 INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[connI[*iter]]);
4502 if(ct!=INTERP_KERNEL::NORM_POLYGON && ct!=INTERP_KERNEL::NORM_QPOLYG)
4503 status=INTERP_KERNEL::PointLocatorAlgos<DummyClsMCUG<SPACEDIM> >::isElementContainsPoint(pos+i*SPACEDIM,ct,coords,conn+connI[*iter]+1,sz,eps);
4507 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPointsAlg : not implemented yet for POLYGON and QPOLYGON in spaceDim 3 !");
4508 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
4509 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
4510 std::vector<INTERP_KERNEL::Node *> nodes(sz);
4511 INTERP_KERNEL::QuadraticPolygon *pol(0);
4512 for(int j=0;j<sz;j++)
4514 int nodeId(conn[connI[*iter]+1+j]);
4515 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*SPACEDIM],coords[nodeId*SPACEDIM+1]);
4517 if(!INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic())
4518 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
4520 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
4521 INTERP_KERNEL::Node *n(new INTERP_KERNEL::Node(pos[i*SPACEDIM],pos[i*SPACEDIM+1]));
4522 double a(0.),b(0.),c(0.);
4523 a=pol->normalizeMe(b,c); n->applySimilarity(b,c,a);
4524 status=pol->isInOrOut2(n);
4525 delete pol; n->decrRef();
4529 eltsIndexPtr[i+1]++;
4530 elts->pushBackSilent(*iter);
4536 * Finds cells in contact with several balls (i.e. points with precision).
4537 * This method is an extension of getCellContainingPoint() and
4538 * getCellsContainingPoint() for the case of multiple points.
4539 * 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.
4540 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4541 * \param [in] pos - an array of coordinates of points in full interlace mode :
4542 * X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4543 * this->getSpaceDimension() * \a nbOfPoints
4544 * \param [in] nbOfPoints - number of points to locate within \a this mesh.
4545 * \param [in] eps - radius of balls (i.e. the precision).
4546 * \param [out] elts - vector returning ids of found cells.
4547 * \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4548 * dividing cell ids in \a elts into groups each referring to one
4549 * point. Its every element (except the last one) is an index pointing to the
4550 * first id of a group of cells. For example cells in contact with the *i*-th
4551 * point are described by following range of indices:
4552 * [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4553 * \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4554 * Number of cells in contact with the *i*-th point is
4555 * \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4556 * \throw If the coordinates array is not set.
4557 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4559 * \if ENABLE_EXAMPLES
4560 * \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4561 * \ref py_mcumesh_getCellsContainingPoints "Here is a Python example".
4564 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, int nbOfPoints, double eps,
4565 MCAuto<DataArrayInt>& elts, MCAuto<DataArrayInt>& eltsIndex) const
4567 int spaceDim=getSpaceDimension();
4568 int mDim=getMeshDimension();
4573 const double *coords=_coords->getConstPointer();
4574 getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4581 throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4583 else if(spaceDim==2)
4587 const double *coords=_coords->getConstPointer();
4588 getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4591 throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4593 else if(spaceDim==1)
4597 const double *coords=_coords->getConstPointer();
4598 getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4601 throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4604 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4608 * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4609 * least two its edges intersect each other anywhere except their extremities. An
4610 * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4611 * \param [in,out] cells - a vector returning ids of the found cells. It is not
4612 * cleared before filling in.
4613 * \param [in] eps - precision.
4614 * \throw If \a this->getMeshDimension() != 2.
4615 * \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4617 void MEDCouplingUMesh::checkButterflyCells(std::vector<int>& cells, double eps) const
4619 const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4620 if(getMeshDimension()!=2)
4621 throw INTERP_KERNEL::Exception(msg);
4622 int spaceDim=getSpaceDimension();
4623 if(spaceDim!=2 && spaceDim!=3)
4624 throw INTERP_KERNEL::Exception(msg);
4625 const int *conn=_nodal_connec->getConstPointer();
4626 const int *connI=_nodal_connec_index->getConstPointer();
4627 int nbOfCells=getNumberOfCells();
4628 std::vector<double> cell2DinS2;
4629 for(int i=0;i<nbOfCells;i++)
4631 int offset=connI[i];
4632 int nbOfNodesForCell=connI[i+1]-offset-1;
4633 if(nbOfNodesForCell<=3)
4635 bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4636 project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4637 if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4644 * This method is typically requested to unbutterfly 2D linear cells in \b this.
4646 * 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.
4647 * 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.
4649 * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4650 * This convex envelop is computed using Jarvis march algorithm.
4651 * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4652 * 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)
4653 * 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.
4655 * \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.
4656 * \sa MEDCouplingUMesh::colinearize2D
4658 DataArrayInt *MEDCouplingUMesh::convexEnvelop2D()
4660 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4661 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D works only for meshDim=2 and spaceDim=2 !");
4662 checkFullyDefined();
4663 const double *coords=getCoords()->getConstPointer();
4664 int nbOfCells=getNumberOfCells();
4665 MCAuto<DataArrayInt> nodalConnecIndexOut=DataArrayInt::New();
4666 nodalConnecIndexOut->alloc(nbOfCells+1,1);
4667 MCAuto<DataArrayInt> nodalConnecOut(DataArrayInt::New());
4668 int *workIndexOut=nodalConnecIndexOut->getPointer();
4670 const int *nodalConnecIn=_nodal_connec->getConstPointer();
4671 const int *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4672 std::set<INTERP_KERNEL::NormalizedCellType> types;
4673 MCAuto<DataArrayInt> isChanged(DataArrayInt::New());
4674 isChanged->alloc(0,1);
4675 for(int i=0;i<nbOfCells;i++,workIndexOut++)
4677 int pos=nodalConnecOut->getNumberOfTuples();
4678 if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4679 isChanged->pushBackSilent(i);
4680 types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4681 workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4683 if(isChanged->empty())
4685 setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4687 return isChanged.retn();
4691 * This method is \b NOT const because it can modify \a this.
4692 * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4693 * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4694 * \param policy specifies the type of extrusion chosen:
4695 * - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4696 * will be repeated to build each level
4697 * - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4698 * 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
4699 * 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
4701 * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4703 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4705 checkFullyDefined();
4706 mesh1D->checkFullyDefined();
4707 if(!mesh1D->isContiguous1D())
4708 throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4709 if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4710 throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4711 if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4712 throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4713 if(mesh1D->getMeshDimension()!=1)
4714 throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4716 if(isPresenceOfQuadratic())
4718 if(mesh1D->isFullyQuadratic())
4721 throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4723 int oldNbOfNodes(getNumberOfNodes());
4724 MCAuto<DataArrayDouble> newCoords;
4729 newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4734 newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4738 throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4740 setCoords(newCoords);
4741 MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4747 * This method works on a 3D curve linear mesh that is to say (meshDim==1 and spaceDim==3).
4748 * If it is not the case an exception will be thrown.
4749 * This method is non const because the coordinate of \a this can be appended with some new points issued from
4750 * intersection of plane defined by ('origin','vec').
4751 * This method has one in/out parameter : 'cut3DCurve'.
4752 * Param 'cut3DCurve' is expected to be of size 'this->getNumberOfCells()'. For each i in [0,'this->getNumberOfCells()')
4753 * if cut3DCurve[i]==-2, it means that for cell #i in \a this nothing has been detected previously.
4754 * if cut3DCurve[i]==-1, it means that cell#i has been already detected to be fully part of plane defined by ('origin','vec').
4755 * This method will throw an exception if \a this contains a non linear segment.
4757 void MEDCouplingUMesh::split3DCurveWithPlane(const double *origin, const double *vec, double eps, std::vector<int>& cut3DCurve)
4759 checkFullyDefined();
4760 if(getMeshDimension()!=1 || getSpaceDimension()!=3)
4761 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane works on umeshes with meshdim equal to 1 and spaceDim equal to 3 !");
4762 int ncells=getNumberOfCells();
4763 int nnodes=getNumberOfNodes();
4764 double vec2[3],vec3[3],vec4[3];
4765 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
4767 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
4768 vec2[0]=vec[0]/normm; vec2[1]=vec[1]/normm; vec2[2]=vec[2]/normm;
4769 const int *conn=_nodal_connec->getConstPointer();
4770 const int *connI=_nodal_connec_index->getConstPointer();
4771 const double *coo=_coords->getConstPointer();
4772 std::vector<double> addCoo;
4773 for(int i=0;i<ncells;i++)
4775 if(conn[connI[i]]==(int)INTERP_KERNEL::NORM_SEG2)
4777 if(cut3DCurve[i]==-2)
4779 int st=conn[connI[i]+1],endd=conn[connI[i]+2];
4780 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];
4781 double normm2=sqrt(vec3[0]*vec3[0]+vec3[1]*vec3[1]+vec3[2]*vec3[2]);
4782 double colin=std::abs((vec3[0]*vec2[0]+vec3[1]*vec2[1]+vec3[2]*vec2[2])/normm2);
4783 if(colin>eps)//if colin<=eps -> current SEG2 is colinear to the input plane
4785 const double *st2=coo+3*st;
4786 vec4[0]=st2[0]-origin[0]; vec4[1]=st2[1]-origin[1]; vec4[2]=st2[2]-origin[2];
4787 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]));
4788 if(pos>eps && pos<1-eps)
4790 int nNode=((int)addCoo.size())/3;
4791 vec4[0]=st2[0]+pos*vec3[0]; vec4[1]=st2[1]+pos*vec3[1]; vec4[2]=st2[2]+pos*vec3[2];
4792 addCoo.insert(addCoo.end(),vec4,vec4+3);
4793 cut3DCurve[i]=nnodes+nNode;
4799 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane : this method is only available for linear cell (NORM_SEG2) !");
4803 int newNbOfNodes=nnodes+((int)addCoo.size())/3;
4804 MCAuto<DataArrayDouble> coo2=DataArrayDouble::New();
4805 coo2->alloc(newNbOfNodes,3);
4806 double *tmp=coo2->getPointer();
4807 tmp=std::copy(_coords->begin(),_coords->end(),tmp);
4808 std::copy(addCoo.begin(),addCoo.end(),tmp);
4809 DataArrayDouble::SetArrayIn(coo2,_coords);
4814 * This method incarnates the policy 0 for MEDCouplingUMesh::buildExtrudedMesh method.
4815 * \param mesh1D is the input 1D mesh used for translation computation.
4816 * \return newCoords new coords filled by this method.
4818 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslation(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4820 int oldNbOfNodes=getNumberOfNodes();
4821 int nbOf1DCells=mesh1D->getNumberOfCells();
4822 int spaceDim=getSpaceDimension();
4823 DataArrayDouble *ret=DataArrayDouble::New();
4824 std::vector<bool> isQuads;
4825 int nbOfLevsInVec=isQuad?2*nbOf1DCells+1:nbOf1DCells+1;
4826 ret->alloc(oldNbOfNodes*nbOfLevsInVec,spaceDim);
4827 double *retPtr=ret->getPointer();
4828 const double *coords=getCoords()->getConstPointer();
4829 double *work=std::copy(coords,coords+spaceDim*oldNbOfNodes,retPtr);
4831 std::vector<double> c;
4835 for(int i=0;i<nbOf1DCells;i++)
4838 mesh1D->getNodeIdsOfCell(i,v);
4840 mesh1D->getCoordinatesOfNode(v[isQuad?2:1],c);
4841 mesh1D->getCoordinatesOfNode(v[0],c);
4842 std::transform(c.begin(),c.begin()+spaceDim,c.begin()+spaceDim,vec,std::minus<double>());
4843 for(int j=0;j<oldNbOfNodes;j++)
4844 work=std::transform(vec,vec+spaceDim,retPtr+spaceDim*(i*oldNbOfNodes+j),work,std::plus<double>());
4848 mesh1D->getCoordinatesOfNode(v[1],c);
4849 mesh1D->getCoordinatesOfNode(v[0],c);
4850 std::transform(c.begin(),c.begin()+spaceDim,c.begin()+spaceDim,vec,std::minus<double>());
4851 for(int j=0;j<oldNbOfNodes;j++)
4852 work=std::transform(vec,vec+spaceDim,retPtr+spaceDim*(i*oldNbOfNodes+j),work,std::plus<double>());
4855 ret->copyStringInfoFrom(*getCoords());
4860 * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4861 * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4862 * \return newCoords new coords filled by this method.
4864 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4866 if(mesh1D->getSpaceDimension()==2)
4867 return fillExtCoordsUsingTranslAndAutoRotation2D(mesh1D,isQuad);
4868 if(mesh1D->getSpaceDimension()==3)
4869 return fillExtCoordsUsingTranslAndAutoRotation3D(mesh1D,isQuad);
4870 throw INTERP_KERNEL::Exception("Not implemented rotation and translation alg. for spacedim other than 2 and 3 !");
4874 * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4875 * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4876 * \return newCoords new coords filled by this method.
4878 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4881 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D : not implemented for quadratic cells !");
4882 int oldNbOfNodes=getNumberOfNodes();
4883 int nbOf1DCells=mesh1D->getNumberOfCells();
4885 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D : impossible to detect any angle of rotation ! Change extrusion policy 1->0 !");
4886 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
4887 int nbOfLevsInVec=nbOf1DCells+1;
4888 ret->alloc(oldNbOfNodes*nbOfLevsInVec,2);
4889 double *retPtr=ret->getPointer();
4890 retPtr=std::copy(getCoords()->getConstPointer(),getCoords()->getConstPointer()+getCoords()->getNbOfElems(),retPtr);
4891 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
4892 MCAuto<DataArrayDouble> tmp2=getCoords()->deepCopy();
4893 tmp->setCoords(tmp2);
4894 const double *coo1D=mesh1D->getCoords()->getConstPointer();
4895 const int *conn1D=mesh1D->getNodalConnectivity()->getConstPointer();
4896 const int *connI1D=mesh1D->getNodalConnectivityIndex()->getConstPointer();
4897 for(int i=1;i<nbOfLevsInVec;i++)
4899 const double *begin=coo1D+2*conn1D[connI1D[i-1]+1];
4900 const double *end=coo1D+2*conn1D[connI1D[i-1]+2];
4901 const double *third=i+1<nbOfLevsInVec?coo1D+2*conn1D[connI1D[i]+2]:coo1D+2*conn1D[connI1D[i-2]+1];
4902 const double vec[2]={end[0]-begin[0],end[1]-begin[1]};
4903 tmp->translate(vec);
4904 double tmp3[2],radius,alpha,alpha0;
4905 const double *p0=i+1<nbOfLevsInVec?begin:third;
4906 const double *p1=i+1<nbOfLevsInVec?end:begin;
4907 const double *p2=i+1<nbOfLevsInVec?third:end;
4908 INTERP_KERNEL::EdgeArcCircle::GetArcOfCirclePassingThru(p0,p1,p2,tmp3,radius,alpha,alpha0);
4909 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]);
4910 double angle=acos(cosangle/(radius*radius));
4911 tmp->rotate(end,0,angle);
4912 retPtr=std::copy(tmp2->getConstPointer(),tmp2->getConstPointer()+tmp2->getNbOfElems(),retPtr);
4918 * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4919 * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4920 * \return newCoords new coords filled by this method.
4922 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4925 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D : not implemented for quadratic cells !");
4926 int oldNbOfNodes=getNumberOfNodes();
4927 int nbOf1DCells=mesh1D->getNumberOfCells();
4929 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D : impossible to detect any angle of rotation ! Change extrusion policy 1->0 !");
4930 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
4931 int nbOfLevsInVec=nbOf1DCells+1;
4932 ret->alloc(oldNbOfNodes*nbOfLevsInVec,3);
4933 double *retPtr=ret->getPointer();
4934 retPtr=std::copy(getCoords()->getConstPointer(),getCoords()->getConstPointer()+getCoords()->getNbOfElems(),retPtr);
4935 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
4936 MCAuto<DataArrayDouble> tmp2=getCoords()->deepCopy();
4937 tmp->setCoords(tmp2);
4938 const double *coo1D=mesh1D->getCoords()->getConstPointer();
4939 const int *conn1D=mesh1D->getNodalConnectivity()->getConstPointer();
4940 const int *connI1D=mesh1D->getNodalConnectivityIndex()->getConstPointer();
4941 for(int i=1;i<nbOfLevsInVec;i++)
4943 const double *begin=coo1D+3*conn1D[connI1D[i-1]+1];
4944 const double *end=coo1D+3*conn1D[connI1D[i-1]+2];
4945 const double *third=i+1<nbOfLevsInVec?coo1D+3*conn1D[connI1D[i]+2]:coo1D+3*conn1D[connI1D[i-2]+1];
4946 const double vec[3]={end[0]-begin[0],end[1]-begin[1],end[2]-begin[2]};
4947 tmp->translate(vec);
4948 double tmp3[2],radius,alpha,alpha0;
4949 const double *p0=i+1<nbOfLevsInVec?begin:third;
4950 const double *p1=i+1<nbOfLevsInVec?end:begin;
4951 const double *p2=i+1<nbOfLevsInVec?third:end;
4952 double vecPlane[3]={
4953 (p1[1]-p0[1])*(p2[2]-p1[2])-(p1[2]-p0[2])*(p2[1]-p1[1]),
4954 (p1[2]-p0[2])*(p2[0]-p1[0])-(p1[0]-p0[0])*(p2[2]-p1[2]),
4955 (p1[0]-p0[0])*(p2[1]-p1[1])-(p1[1]-p0[1])*(p2[0]-p1[0]),
4957 double norm=sqrt(vecPlane[0]*vecPlane[0]+vecPlane[1]*vecPlane[1]+vecPlane[2]*vecPlane[2]);
4960 vecPlane[0]/=norm; vecPlane[1]/=norm; vecPlane[2]/=norm;
4961 double norm2=sqrt(vecPlane[0]*vecPlane[0]+vecPlane[1]*vecPlane[1]);
4962 double vec2[2]={vecPlane[1]/norm2,-vecPlane[0]/norm2};
4964 double c2=cos(asin(s2));
4966 {vec2[0]*vec2[0]*(1-c2)+c2, vec2[0]*vec2[1]*(1-c2), vec2[1]*s2},
4967 {vec2[0]*vec2[1]*(1-c2), vec2[1]*vec2[1]*(1-c2)+c2, -vec2[0]*s2},
4968 {-vec2[1]*s2, vec2[0]*s2, c2}
4970 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]};
4971 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]};
4972 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]};
4973 INTERP_KERNEL::EdgeArcCircle::GetArcOfCirclePassingThru(p0r,p1r,p2r,tmp3,radius,alpha,alpha0);
4974 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]);
4975 double angle=acos(cosangle/(radius*radius));
4976 tmp->rotate(end,vecPlane,angle);
4978 retPtr=std::copy(tmp2->getConstPointer(),tmp2->getConstPointer()+tmp2->getNbOfElems(),retPtr);
4984 * This method is private because not easy to use for end user. This method is const contrary to
4985 * MEDCouplingUMesh::buildExtrudedMesh method because this->_coords are expected to contain
4986 * the coords sorted slice by slice.
4987 * \param isQuad specifies presence of quadratic cells.
4989 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMeshFromThisLowLev(int nbOfNodesOf1Lev, bool isQuad) const
4991 int nbOf1DCells(getNumberOfNodes()/nbOfNodesOf1Lev-1);
4992 int nbOf2DCells(getNumberOfCells());
4993 int nbOf3DCells(nbOf2DCells*nbOf1DCells);
4994 MEDCouplingUMesh *ret(MEDCouplingUMesh::New("Extruded",getMeshDimension()+1));
4995 const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
4996 MCAuto<DataArrayInt> newConn(DataArrayInt::New()),newConnI(DataArrayInt::New());
4997 newConnI->alloc(nbOf3DCells+1,1);
4998 int *newConnIPtr(newConnI->getPointer());
5000 std::vector<int> newc;
5001 for(int j=0;j<nbOf2DCells;j++)
5003 AppendExtrudedCell(conn+connI[j],conn+connI[j+1],nbOfNodesOf1Lev,isQuad,newc);
5004 *newConnIPtr++=(int)newc.size();
5006 newConn->alloc((int)(newc.size())*nbOf1DCells,1);
5007 int *newConnPtr(newConn->getPointer());
5008 int deltaPerLev(isQuad?2*nbOfNodesOf1Lev:nbOfNodesOf1Lev);
5009 newConnIPtr=newConnI->getPointer();
5010 for(int iz=0;iz<nbOf1DCells;iz++)
5013 std::transform(newConnIPtr+1,newConnIPtr+1+nbOf2DCells,newConnIPtr+1+iz*nbOf2DCells,std::bind2nd(std::plus<int>(),newConnIPtr[iz*nbOf2DCells]));
5014 const int *posOfTypeOfCell(newConnIPtr);
5015 for(std::vector<int>::const_iterator iter=newc.begin();iter!=newc.end();iter++,newConnPtr++)
5017 int icell((int)(iter-newc.begin()));//std::distance unfortunately cannot been called here in C++98
5018 if(icell!=*posOfTypeOfCell)
5021 *newConnPtr=(*iter)+iz*deltaPerLev;
5032 ret->setConnectivity(newConn,newConnI,true);
5033 ret->setCoords(getCoords());
5038 * Checks if \a this mesh is constituted by only quadratic cells.
5039 * \return bool - \c true if there are only quadratic cells in \a this mesh.
5040 * \throw If the coordinates array is not set.
5041 * \throw If the nodal connectivity of cells is not defined.
5043 bool MEDCouplingUMesh::isFullyQuadratic() const
5045 checkFullyDefined();
5047 int nbOfCells=getNumberOfCells();
5048 for(int i=0;i<nbOfCells && ret;i++)
5050 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5051 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5052 ret=cm.isQuadratic();
5058 * Checks if \a this mesh includes any quadratic cell.
5059 * \return bool - \c true if there is at least one quadratic cells in \a this mesh.
5060 * \throw If the coordinates array is not set.
5061 * \throw If the nodal connectivity of cells is not defined.
5063 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
5065 checkFullyDefined();
5067 int nbOfCells=getNumberOfCells();
5068 for(int i=0;i<nbOfCells && !ret;i++)
5070 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5071 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5072 ret=cm.isQuadratic();
5078 * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
5079 * this mesh, it remains unchanged.
5080 * \throw If the coordinates array is not set.
5081 * \throw If the nodal connectivity of cells is not defined.
5083 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
5085 checkFullyDefined();
5086 int nbOfCells=getNumberOfCells();
5088 const int *iciptr=_nodal_connec_index->getConstPointer();
5089 for(int i=0;i<nbOfCells;i++)
5091 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5092 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5093 if(cm.isQuadratic())
5095 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
5096 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
5097 if(!cml.isDynamic())
5098 delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
5100 delta+=(iciptr[i+1]-iciptr[i]-1)/2;
5105 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5106 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5107 const int *icptr=_nodal_connec->getConstPointer();
5108 newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
5109 newConnI->alloc(nbOfCells+1,1);
5110 int *ocptr=newConn->getPointer();
5111 int *ociptr=newConnI->getPointer();
5114 for(int i=0;i<nbOfCells;i++,ociptr++)
5116 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
5117 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5118 if(!cm.isQuadratic())
5120 _types.insert(type);
5121 ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
5122 ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
5126 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
5127 _types.insert(typel);
5128 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
5129 int newNbOfNodes=cml.getNumberOfNodes();
5131 newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
5132 *ocptr++=(int)typel;
5133 ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
5134 ociptr[1]=ociptr[0]+newNbOfNodes+1;
5137 setConnectivity(newConn,newConnI,false);
5141 * This method converts all linear cell in \a this to quadratic one.
5142 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
5143 * 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)
5144 * 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.
5145 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
5146 * end of the existing coordinates.
5148 * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
5149 * corresponding quadratic cells. 1 is those creating the 'most' complex.
5150 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5152 * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
5154 * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
5156 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
5158 DataArrayInt *conn=0,*connI=0;
5159 DataArrayDouble *coords=0;
5160 std::set<INTERP_KERNEL::NormalizedCellType> types;
5161 checkFullyDefined();
5162 MCAuto<DataArrayInt> ret,connSafe,connISafe;
5163 MCAuto<DataArrayDouble> coordsSafe;
5164 int meshDim=getMeshDimension();
5165 switch(conversionType)
5171 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
5172 connSafe=conn; connISafe=connI; coordsSafe=coords;
5175 ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
5176 connSafe=conn; connISafe=connI; coordsSafe=coords;
5179 ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
5180 connSafe=conn; connISafe=connI; coordsSafe=coords;
5183 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
5191 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
5192 connSafe=conn; connISafe=connI; coordsSafe=coords;
5195 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
5196 connSafe=conn; connISafe=connI; coordsSafe=coords;
5199 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
5200 connSafe=conn; connISafe=connI; coordsSafe=coords;
5203 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
5208 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
5210 setConnectivity(connSafe,connISafe,false);
5212 setCoords(coordsSafe);
5217 * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
5218 * so that the number of cells remains the same. Quadratic faces are converted to
5219 * polygons. This method works only for 2D meshes in
5220 * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
5221 * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
5222 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5223 * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
5224 * a polylinized edge constituting the input polygon.
5225 * \throw If the coordinates array is not set.
5226 * \throw If the nodal connectivity of cells is not defined.
5227 * \throw If \a this->getMeshDimension() != 2.
5228 * \throw If \a this->getSpaceDimension() != 2.
5230 void MEDCouplingUMesh::tessellate2D(double eps)
5232 int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
5234 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
5238 return tessellate2DCurveInternal(eps);
5240 return tessellate2DInternal(eps);
5242 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
5246 * Tessellates \a this 1D mesh in 2D space by dividing not straight quadratic edges.
5247 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5248 * \param [in] eps - specifies the maximal angle (in radian) between 2 sub-edges of
5249 * a sub-divided edge.
5250 * \throw If the coordinates array is not set.
5251 * \throw If the nodal connectivity of cells is not defined.
5252 * \throw If \a this->getMeshDimension() != 1.
5253 * \throw If \a this->getSpaceDimension() != 2.
5258 * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
5259 * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
5260 * The nodes to be added in those 2D cells are defined by the pair of \a nodeIdsToAdd and \a nodeIdsIndexToAdd.
5261 * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
5262 * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
5263 * This method can be seen as the opposite method of colinearize2D.
5264 * 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
5265 * to avoid to modify the numbering of existing nodes.
5267 * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
5268 * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
5269 * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
5270 * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
5271 * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
5272 * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
5273 * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
5275 * \sa buildDescendingConnectivity2
5277 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayInt *nodeIdsToAdd, const DataArrayInt *nodeIdsIndexToAdd, const DataArrayInt *edgeIdsToBeSplit,
5278 const MEDCouplingUMesh *mesh1Desc, const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *revDesc, const DataArrayInt *revDescI)
5280 if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
5281 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
5282 nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
5283 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
5284 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
5285 if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
5286 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
5287 //DataArrayInt *out0(0),*outi0(0);
5288 //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
5289 //MCAuto<DataArrayInt> out0s(out0),outi0s(outi0);
5290 //out0s=out0s->buildUnique(); out0s->sort(true);
5295 * Implementes \a conversionType 0 for meshes with meshDim = 1, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5296 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5297 * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5299 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic1D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5301 MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5302 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5303 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5304 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5305 int nbOfCells=getNumberOfCells();
5306 int nbOfNodes=getNumberOfNodes();
5307 const int *cPtr=_nodal_connec->getConstPointer();
5308 const int *icPtr=_nodal_connec_index->getConstPointer();
5309 int lastVal=0,offset=nbOfNodes;
5310 for(int i=0;i<nbOfCells;i++,icPtr++)
5312 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5313 if(type==INTERP_KERNEL::NORM_SEG2)
5315 types.insert(INTERP_KERNEL::NORM_SEG3);
5316 newConn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG3);
5317 newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[0]+3);
5318 newConn->pushBackSilent(offset++);
5320 newConnI->pushBackSilent(lastVal);
5321 ret->pushBackSilent(i);
5326 lastVal+=(icPtr[1]-icPtr[0]);
5327 newConnI->pushBackSilent(lastVal);
5328 newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5331 MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5332 coords=DataArrayDouble::Aggregate(getCoords(),tmp); conn=newConn.retn(); connI=newConnI.retn();
5336 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
5338 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5339 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5340 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5342 const int *descPtr(desc->begin()),*descIPtr(descI->begin());
5343 DataArrayInt *conn1D=0,*conn1DI=0;
5344 std::set<INTERP_KERNEL::NormalizedCellType> types1D;
5345 DataArrayDouble *coordsTmp=0;
5346 MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=0;
5347 MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5348 MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5349 const int *c1DPtr=conn1D->begin();
5350 const int *c1DIPtr=conn1DI->begin();
5351 int nbOfCells=getNumberOfCells();
5352 const int *cPtr=_nodal_connec->getConstPointer();
5353 const int *icPtr=_nodal_connec_index->getConstPointer();
5355 for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++)
5357 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5358 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5359 if(!cm.isQuadratic())
5361 INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType();
5362 types.insert(typ2); newConn->pushBackSilent(typ2);
5363 newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5364 for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5365 newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5366 lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0]);
5367 newConnI->pushBackSilent(lastVal);
5368 ret->pushBackSilent(i);
5373 lastVal+=(icPtr[1]-icPtr[0]);
5374 newConnI->pushBackSilent(lastVal);
5375 newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5378 conn=newConn.retn(); connI=newConnI.retn(); coords=coordsTmpSafe.retn();
5383 * Implementes \a conversionType 0 for meshes with meshDim = 2, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5384 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5385 * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5387 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic2D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5389 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5390 MCAuto<MEDCouplingUMesh> m1D=buildDescendingConnectivity(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5391 return convertLinearCellsToQuadratic2DAnd3D0(m1D,desc,descI,conn,connI,coords,types);
5394 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic2D1(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5396 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5397 MCAuto<MEDCouplingUMesh> m1D=buildDescendingConnectivity(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5399 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5400 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5401 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5403 MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5404 const int *descPtr(desc->begin()),*descIPtr(descI->begin());
5405 DataArrayInt *conn1D=0,*conn1DI=0;
5406 std::set<INTERP_KERNEL::NormalizedCellType> types1D;
5407 DataArrayDouble *coordsTmp=0;
5408 MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=0;
5409 MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5410 MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5411 const int *c1DPtr=conn1D->begin();
5412 const int *c1DIPtr=conn1DI->begin();
5413 int nbOfCells=getNumberOfCells();
5414 const int *cPtr=_nodal_connec->getConstPointer();
5415 const int *icPtr=_nodal_connec_index->getConstPointer();
5416 int lastVal=0,offset=coordsTmpSafe->getNumberOfTuples();
5417 for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++)
5419 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5420 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5421 if(!cm.isQuadratic())
5423 INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType2();
5424 types.insert(typ2); newConn->pushBackSilent(typ2);
5425 newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5426 for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5427 newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5428 newConn->pushBackSilent(offset+ret->getNumberOfTuples());
5429 lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0])+1;
5430 newConnI->pushBackSilent(lastVal);
5431 ret->pushBackSilent(i);
5436 lastVal+=(icPtr[1]-icPtr[0]);
5437 newConnI->pushBackSilent(lastVal);
5438 newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5441 MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5442 coords=DataArrayDouble::Aggregate(coordsTmpSafe,tmp); conn=newConn.retn(); connI=newConnI.retn();
5447 * Implementes \a conversionType 0 for meshes with meshDim = 3, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5448 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5449 * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5451 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic3D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5453 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5454 MCAuto<MEDCouplingUMesh> m1D=explode3DMeshTo1D(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5455 return convertLinearCellsToQuadratic2DAnd3D0(m1D,desc,descI,conn,connI,coords,types);
5458 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic3D1(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5460 MCAuto<DataArrayInt> desc2(DataArrayInt::New()),desc2I(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5461 MCAuto<MEDCouplingUMesh> m2D=buildDescendingConnectivityGen<MinusOneSonsGeneratorBiQuadratic>(desc2,desc2I,tmp2,tmp3,MEDCouplingFastNbrer); tmp2=0; tmp3=0;
5462 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),desc1I(DataArrayInt::New()),tmp4(DataArrayInt::New()),tmp5(DataArrayInt::New());
5463 MCAuto<MEDCouplingUMesh> m1D=explode3DMeshTo1D(desc1,desc1I,tmp4,tmp5); tmp4=0; tmp5=0;
5465 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5466 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5467 MCAuto<DataArrayInt> ret=DataArrayInt::New(),ret2=DataArrayInt::New(); ret->alloc(0,1); ret2->alloc(0,1);
5469 MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5470 const int *descPtr(desc1->begin()),*descIPtr(desc1I->begin()),*desc2Ptr(desc2->begin()),*desc2IPtr(desc2I->begin());
5471 DataArrayInt *conn1D=0,*conn1DI=0,*conn2D=0,*conn2DI=0;
5472 std::set<INTERP_KERNEL::NormalizedCellType> types1D,types2D;
5473 DataArrayDouble *coordsTmp=0,*coordsTmp2=0;
5474 MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=DataArrayInt::New(); ret1D->alloc(0,1);
5475 MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5476 MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5477 MCAuto<DataArrayInt> ret2D=m2D->convertLinearCellsToQuadratic2D1(conn2D,conn2DI,coordsTmp2,types2D); ret2D=DataArrayInt::New(); ret2D->alloc(0,1);
5478 MCAuto<DataArrayDouble> coordsTmp2Safe(coordsTmp2);
5479 MCAuto<DataArrayInt> conn2DSafe(conn2D),conn2DISafe(conn2DI);
5480 const int *c1DPtr=conn1D->begin(),*c1DIPtr=conn1DI->begin(),*c2DPtr=conn2D->begin(),*c2DIPtr=conn2DI->begin();
5481 int nbOfCells=getNumberOfCells();
5482 const int *cPtr=_nodal_connec->getConstPointer();
5483 const int *icPtr=_nodal_connec_index->getConstPointer();
5484 int lastVal=0,offset=coordsTmpSafe->getNumberOfTuples();
5485 for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++,desc2IPtr++)
5487 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5488 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5489 if(!cm.isQuadratic())
5491 INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType2();
5492 if(typ2==INTERP_KERNEL::NORM_ERROR)
5494 std::ostringstream oss; oss << "MEDCouplingUMesh::convertLinearCellsToQuadratic3D1 : On cell #" << i << " the linear cell type does not support advanced quadratization !";
5495 throw INTERP_KERNEL::Exception(oss.str().c_str());
5497 types.insert(typ2); newConn->pushBackSilent(typ2);
5498 newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5499 for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5500 newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5501 for(const int *d=desc2Ptr+desc2IPtr[0];d!=desc2Ptr+desc2IPtr[1];d++)
5503 int nodeId2=c2DPtr[c2DIPtr[(*d)+1]-1];
5504 int tmpPos=newConn->getNumberOfTuples();
5505 newConn->pushBackSilent(nodeId2);
5506 ret2D->pushBackSilent(nodeId2); ret1D->pushBackSilent(tmpPos);
5508 newConn->pushBackSilent(offset+ret->getNumberOfTuples());
5509 lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0])+(desc2IPtr[1]-desc2IPtr[0])+1;
5510 newConnI->pushBackSilent(lastVal);
5511 ret->pushBackSilent(i);
5516 lastVal+=(icPtr[1]-icPtr[0]);
5517 newConnI->pushBackSilent(lastVal);
5518 newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5521 MCAuto<DataArrayInt> diffRet2D=ret2D->getDifferentValues();
5522 MCAuto<DataArrayInt> o2nRet2D=diffRet2D->invertArrayN2O2O2N(coordsTmp2Safe->getNumberOfTuples());
5523 coordsTmp2Safe=coordsTmp2Safe->selectByTupleId(diffRet2D->begin(),diffRet2D->end());
5524 MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5525 std::vector<const DataArrayDouble *> v(3); v[0]=coordsTmpSafe; v[1]=coordsTmp2Safe; v[2]=tmp;
5526 int *c=newConn->getPointer();
5527 const int *cI(newConnI->begin());
5528 for(const int *elt=ret1D->begin();elt!=ret1D->end();elt++)
5529 c[*elt]=o2nRet2D->getIJ(c[*elt],0)+offset;
5530 offset=coordsTmp2Safe->getNumberOfTuples();
5531 for(const int *elt=ret->begin();elt!=ret->end();elt++)
5532 c[cI[(*elt)+1]-1]+=offset;
5533 coords=DataArrayDouble::Aggregate(v); conn=newConn.retn(); connI=newConnI.retn();
5538 * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
5539 * In addition, returns an array mapping new cells to old ones. <br>
5540 * This method typically increases the number of cells in \a this mesh
5541 * but the number of nodes remains \b unchanged.
5542 * That's why the 3D splitting policies
5543 * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
5544 * \param [in] policy - specifies a pattern used for splitting.
5545 * The semantic of \a policy is:
5546 * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
5547 * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
5548 * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8 into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
5549 * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8 into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
5552 * \return DataArrayInt * - a new instance of DataArrayInt holding, for each new cell,
5553 * an id of old cell producing it. The caller is to delete this array using
5554 * decrRef() as it is no more needed.
5556 * \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
5557 * \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
5558 * and \a this->getMeshDimension() != 3.
5559 * \throw If \a policy is not one of the four discussed above.
5560 * \throw If the nodal connectivity of cells is not defined.
5561 * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
5563 DataArrayInt *MEDCouplingUMesh::simplexize(int policy)
5568 return simplexizePol0();
5570 return simplexizePol1();
5571 case (int) INTERP_KERNEL::PLANAR_FACE_5:
5572 return simplexizePlanarFace5();
5573 case (int) INTERP_KERNEL::PLANAR_FACE_6:
5574 return simplexizePlanarFace6();
5576 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)");
5581 * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
5582 * - 1D: INTERP_KERNEL::NORM_SEG2
5583 * - 2D: INTERP_KERNEL::NORM_TRI3
5584 * - 3D: INTERP_KERNEL::NORM_TETRA4.
5586 * This method is useful for users that need to use P1 field services as
5587 * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
5588 * All these methods need mesh support containing only simplex cells.
5589 * \return bool - \c true if there are only simplex cells in \a this mesh.
5590 * \throw If the coordinates array is not set.
5591 * \throw If the nodal connectivity of cells is not defined.
5592 * \throw If \a this->getMeshDimension() < 1.
5594 bool MEDCouplingUMesh::areOnlySimplexCells() const
5596 checkFullyDefined();
5597 int mdim=getMeshDimension();
5598 if(mdim<1 || mdim>3)
5599 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
5600 int nbCells=getNumberOfCells();
5601 const int *conn=_nodal_connec->getConstPointer();
5602 const int *connI=_nodal_connec_index->getConstPointer();
5603 for(int i=0;i<nbCells;i++)
5605 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5613 * This method implements policy 0 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5615 DataArrayInt *MEDCouplingUMesh::simplexizePol0()
5617 checkConnectivityFullyDefined();
5618 if(getMeshDimension()!=2)
5619 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePol0 : this policy is only available for mesh with meshdim == 2 !");
5620 int nbOfCells=getNumberOfCells();
5621 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5622 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_QUAD4);
5623 ret->alloc(nbOfCells+nbOfCutCells,1);
5624 if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5625 int *retPt=ret->getPointer();
5626 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5627 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5628 newConnI->alloc(nbOfCells+nbOfCutCells+1,1);
5629 newConn->alloc(getNodalConnectivityArrayLen()+3*nbOfCutCells,1);
5630 int *pt=newConn->getPointer();
5631 int *ptI=newConnI->getPointer();
5633 const int *oldc=_nodal_connec->getConstPointer();
5634 const int *ci=_nodal_connec_index->getConstPointer();
5635 for(int i=0;i<nbOfCells;i++,ci++)
5637 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_QUAD4)
5639 const int tmp[8]={(int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+2],oldc[ci[0]+3],
5640 (int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+3],oldc[ci[0]+4]};
5641 pt=std::copy(tmp,tmp+8,pt);
5650 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5651 ptI[1]=ptI[0]+ci[1]-ci[0];
5656 _nodal_connec->decrRef();
5657 _nodal_connec=newConn.retn();
5658 _nodal_connec_index->decrRef();
5659 _nodal_connec_index=newConnI.retn();
5666 * This method implements policy 1 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5668 DataArrayInt *MEDCouplingUMesh::simplexizePol1()
5670 checkConnectivityFullyDefined();
5671 if(getMeshDimension()!=2)
5672 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePol0 : this policy is only available for mesh with meshdim == 2 !");
5673 int nbOfCells=getNumberOfCells();
5674 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5675 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_QUAD4);
5676 ret->alloc(nbOfCells+nbOfCutCells,1);
5677 if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5678 int *retPt=ret->getPointer();
5679 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5680 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5681 newConnI->alloc(nbOfCells+nbOfCutCells+1,1);
5682 newConn->alloc(getNodalConnectivityArrayLen()+3*nbOfCutCells,1);
5683 int *pt=newConn->getPointer();
5684 int *ptI=newConnI->getPointer();
5686 const int *oldc=_nodal_connec->getConstPointer();
5687 const int *ci=_nodal_connec_index->getConstPointer();
5688 for(int i=0;i<nbOfCells;i++,ci++)
5690 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_QUAD4)
5692 const int tmp[8]={(int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+2],oldc[ci[0]+4],
5693 (int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+2],oldc[ci[0]+3],oldc[ci[0]+4]};
5694 pt=std::copy(tmp,tmp+8,pt);
5703 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5704 ptI[1]=ptI[0]+ci[1]-ci[0];
5709 _nodal_connec->decrRef();
5710 _nodal_connec=newConn.retn();
5711 _nodal_connec_index->decrRef();
5712 _nodal_connec_index=newConnI.retn();
5719 * This method implements policy INTERP_KERNEL::PLANAR_FACE_5 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5721 DataArrayInt *MEDCouplingUMesh::simplexizePlanarFace5()
5723 checkConnectivityFullyDefined();
5724 if(getMeshDimension()!=3)
5725 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePlanarFace5 : this policy is only available for mesh with meshdim == 3 !");
5726 int nbOfCells=getNumberOfCells();
5727 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5728 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_HEXA8);
5729 ret->alloc(nbOfCells+4*nbOfCutCells,1);
5730 if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5731 int *retPt=ret->getPointer();
5732 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5733 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5734 newConnI->alloc(nbOfCells+4*nbOfCutCells+1,1);
5735 newConn->alloc(getNodalConnectivityArrayLen()+16*nbOfCutCells,1);//21
5736 int *pt=newConn->getPointer();
5737 int *ptI=newConnI->getPointer();
5739 const int *oldc=_nodal_connec->getConstPointer();
5740 const int *ci=_nodal_connec_index->getConstPointer();
5741 for(int i=0;i<nbOfCells;i++,ci++)
5743 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_HEXA8)
5745 for(int j=0;j<5;j++,pt+=5,ptI++)
5747 pt[0]=(int)INTERP_KERNEL::NORM_TETRA4;
5748 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];
5755 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5756 ptI[1]=ptI[0]+ci[1]-ci[0];
5761 _nodal_connec->decrRef();
5762 _nodal_connec=newConn.retn();
5763 _nodal_connec_index->decrRef();
5764 _nodal_connec_index=newConnI.retn();
5771 * This method implements policy INTERP_KERNEL::PLANAR_FACE_6 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5773 DataArrayInt *MEDCouplingUMesh::simplexizePlanarFace6()
5775 checkConnectivityFullyDefined();
5776 if(getMeshDimension()!=3)
5777 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePlanarFace6 : this policy is only available for mesh with meshdim == 3 !");
5778 int nbOfCells=getNumberOfCells();
5779 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5780 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_HEXA8);
5781 ret->alloc(nbOfCells+5*nbOfCutCells,1);
5782 if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5783 int *retPt=ret->getPointer();
5784 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5785 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5786 newConnI->alloc(nbOfCells+5*nbOfCutCells+1,1);
5787 newConn->alloc(getNodalConnectivityArrayLen()+21*nbOfCutCells,1);
5788 int *pt=newConn->getPointer();
5789 int *ptI=newConnI->getPointer();
5791 const int *oldc=_nodal_connec->getConstPointer();
5792 const int *ci=_nodal_connec_index->getConstPointer();
5793 for(int i=0;i<nbOfCells;i++,ci++)
5795 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_HEXA8)
5797 for(int j=0;j<6;j++,pt+=5,ptI++)
5799 pt[0]=(int)INTERP_KERNEL::NORM_TETRA4;
5800 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];
5807 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5808 ptI[1]=ptI[0]+ci[1]-ci[0];
5813 _nodal_connec->decrRef();
5814 _nodal_connec=newConn.retn();
5815 _nodal_connec_index->decrRef();
5816 _nodal_connec_index=newConnI.retn();
5823 * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
5824 * so that the number of cells remains the same. Quadratic faces are converted to
5825 * polygons. This method works only for 2D meshes in
5826 * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
5827 * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
5828 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5829 * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
5830 * a polylinized edge constituting the input polygon.
5831 * \throw If the coordinates array is not set.
5832 * \throw If the nodal connectivity of cells is not defined.
5833 * \throw If \a this->getMeshDimension() != 2.
5834 * \throw If \a this->getSpaceDimension() != 2.
5836 void MEDCouplingUMesh::tessellate2DInternal(double eps)
5838 checkFullyDefined();
5839 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
5840 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DInternal works on umeshes with meshdim equal to 2 and spaceDim equal to 2 too!");
5841 double epsa=fabs(eps);
5842 if(epsa<std::numeric_limits<double>::min())
5843 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 !");
5844 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
5845 MCAuto<MEDCouplingUMesh> mDesc(buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1));
5846 revDesc1=0; revDescIndx1=0;
5847 mDesc->tessellate2D(eps);
5848 subDivide2DMesh(mDesc->_nodal_connec->getConstPointer(),mDesc->_nodal_connec_index->getConstPointer(),desc1->getConstPointer(),descIndx1->getConstPointer());
5849 setCoords(mDesc->getCoords());
5853 * Tessellates \a this 1D mesh in 2D space by dividing not straight quadratic edges.
5854 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5855 * \param [in] eps - specifies the maximal angle (in radian) between 2 sub-edges of
5856 * a sub-divided edge.
5857 * \throw If the coordinates array is not set.
5858 * \throw If the nodal connectivity of cells is not defined.
5859 * \throw If \a this->getMeshDimension() != 1.
5860 * \throw If \a this->getSpaceDimension() != 2.
5862 void MEDCouplingUMesh::tessellate2DCurveInternal(double eps)
5864 checkFullyDefined();
5865 if(getMeshDimension()!=1 || getSpaceDimension()!=2)
5866 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DCurveInternal works on umeshes with meshdim equal to 1 and spaceDim equal to 2 too!");
5867 double epsa=fabs(eps);
5868 if(epsa<std::numeric_limits<double>::min())
5869 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 !");
5870 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=1.e-10;
5871 int nbCells=getNumberOfCells();
5872 int nbNodes=getNumberOfNodes();
5873 const int *conn=_nodal_connec->getConstPointer();
5874 const int *connI=_nodal_connec_index->getConstPointer();
5875 const double *coords=_coords->getConstPointer();
5876 std::vector<double> addCoo;
5877 std::vector<int> newConn;//no direct DataArrayInt because interface with Geometric2D
5878 MCAuto<DataArrayInt> newConnI(DataArrayInt::New());
5879 newConnI->alloc(nbCells+1,1);
5880 int *newConnIPtr=newConnI->getPointer();
5883 INTERP_KERNEL::Node *tmp2[3];
5884 std::set<INTERP_KERNEL::NormalizedCellType> types;
5885 for(int i=0;i<nbCells;i++,newConnIPtr++)
5887 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5888 if(cm.isQuadratic())
5889 {//assert(connI[i+1]-connI[i]-1==3)
5890 tmp1[0]=conn[connI[i]+1+0]; tmp1[1]=conn[connI[i]+1+1]; tmp1[2]=conn[connI[i]+1+2];
5891 tmp2[0]=new INTERP_KERNEL::Node(coords[2*tmp1[0]],coords[2*tmp1[0]+1]);
5892 tmp2[1]=new INTERP_KERNEL::Node(coords[2*tmp1[1]],coords[2*tmp1[1]+1]);
5893 tmp2[2]=new INTERP_KERNEL::Node(coords[2*tmp1[2]],coords[2*tmp1[2]+1]);
5894 INTERP_KERNEL::EdgeArcCircle *eac=INTERP_KERNEL::EdgeArcCircle::BuildFromNodes(tmp2[0],tmp2[2],tmp2[1]);
5897 eac->tesselate(tmp1,nbNodes,epsa,newConn,addCoo);
5898 types.insert((INTERP_KERNEL::NormalizedCellType)newConn[newConnIPtr[0]]);
5900 newConnIPtr[1]=(int)newConn.size();
5904 types.insert(INTERP_KERNEL::NORM_SEG2);
5905 newConn.push_back(INTERP_KERNEL::NORM_SEG2);
5906 newConn.insert(newConn.end(),conn+connI[i]+1,conn+connI[i]+3);
5907 newConnIPtr[1]=newConnIPtr[0]+3;
5912 types.insert((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5913 newConn.insert(newConn.end(),conn+connI[i],conn+connI[i+1]);
5914 newConnIPtr[1]=newConnIPtr[0]+3;
5917 if(addCoo.empty() && ((int)newConn.size())==_nodal_connec->getNumberOfTuples())//nothing happens during tessellation : no update needed
5920 DataArrayInt::SetArrayIn(newConnI,_nodal_connec_index);
5921 MCAuto<DataArrayInt> newConnArr=DataArrayInt::New();
5922 newConnArr->alloc((int)newConn.size(),1);
5923 std::copy(newConn.begin(),newConn.end(),newConnArr->getPointer());
5924 DataArrayInt::SetArrayIn(newConnArr,_nodal_connec);
5925 MCAuto<DataArrayDouble> newCoords=DataArrayDouble::New();
5926 newCoords->alloc(nbNodes+((int)addCoo.size())/2,2);
5927 double *work=std::copy(_coords->begin(),_coords->end(),newCoords->getPointer());
5928 std::copy(addCoo.begin(),addCoo.end(),work);
5929 DataArrayDouble::SetArrayIn(newCoords,_coords);
5934 * 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.
5935 * This method completly ignore coordinates.
5936 * \param nodeSubdived is the nodal connectivity of subdivision of edges
5937 * \param nodeIndxSubdived is the nodal connectivity index of subdivision of edges
5938 * \param desc is descending connectivity in format specified in MEDCouplingUMesh::buildDescendingConnectivity2
5939 * \param descIndex is descending connectivity index in format specified in MEDCouplingUMesh::buildDescendingConnectivity2
5941 void MEDCouplingUMesh::subDivide2DMesh(const int *nodeSubdived, const int *nodeIndxSubdived, const int *desc, const int *descIndex)
5943 checkFullyDefined();
5944 if(getMeshDimension()!=2)
5945 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::subDivide2DMesh : works only on umesh with meshdim==2 !");
5946 int nbOfCells=getNumberOfCells();
5947 int *connI=_nodal_connec_index->getPointer();
5949 for(int i=0;i<nbOfCells;i++,connI++)
5951 int offset=descIndex[i];
5952 int nbOfEdges=descIndex[i+1]-offset;
5954 bool ddirect=desc[offset+nbOfEdges-1]>0;
5955 int eedgeId=std::abs(desc[offset+nbOfEdges-1])-1;
5956 int ref=ddirect?nodeSubdived[nodeIndxSubdived[eedgeId+1]-1]:nodeSubdived[nodeIndxSubdived[eedgeId]+1];
5957 for(int j=0;j<nbOfEdges;j++)
5959 bool direct=desc[offset+j]>0;
5960 int edgeId=std::abs(desc[offset+j])-1;
5961 if(!INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodeSubdived[nodeIndxSubdived[edgeId]]).isQuadratic())
5963 int id1=nodeSubdived[nodeIndxSubdived[edgeId]+1];
5964 int id2=nodeSubdived[nodeIndxSubdived[edgeId+1]-1];
5965 int ref2=direct?id1:id2;
5968 int nbOfSubNodes=nodeIndxSubdived[edgeId+1]-nodeIndxSubdived[edgeId]-1;
5969 newConnLgth+=nbOfSubNodes-1;
5974 std::ostringstream oss; oss << "MEDCouplingUMesh::subDivide2DMesh : On polygon #" << i << " edgeid #" << j << " subedges mismatch : end subedge k!=start subedge k+1 !";
5975 throw INTERP_KERNEL::Exception(oss.str().c_str());
5980 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::subDivide2DMesh : this method only subdivides into linear edges !");
5983 newConnLgth++;//+1 is for cell type
5984 connI[1]=newConnLgth;
5987 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5988 newConn->alloc(newConnLgth,1);
5989 int *work=newConn->getPointer();
5990 for(int i=0;i<nbOfCells;i++)
5992 *work++=INTERP_KERNEL::NORM_POLYGON;
5993 int offset=descIndex[i];
5994 int nbOfEdges=descIndex[i+1]-offset;
5995 for(int j=0;j<nbOfEdges;j++)
5997 bool direct=desc[offset+j]>0;
5998 int edgeId=std::abs(desc[offset+j])-1;
6000 work=std::copy(nodeSubdived+nodeIndxSubdived[edgeId]+1,nodeSubdived+nodeIndxSubdived[edgeId+1]-1,work);
6003 int nbOfSubNodes=nodeIndxSubdived[edgeId+1]-nodeIndxSubdived[edgeId]-1;
6004 std::reverse_iterator<const int *> it(nodeSubdived+nodeIndxSubdived[edgeId+1]);
6005 work=std::copy(it,it+nbOfSubNodes-1,work);
6009 DataArrayInt::SetArrayIn(newConn,_nodal_connec);
6012 _types.insert(INTERP_KERNEL::NORM_POLYGON);
6016 * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
6017 * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
6018 * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell. This method
6019 * does \b not perform geometrical checks and checks only nodal connectivity of cells,
6020 * so it can be useful to call mergeNodes() before calling this method.
6021 * \throw If \a this->getMeshDimension() <= 1.
6022 * \throw If the coordinates array is not set.
6023 * \throw If the nodal connectivity of cells is not defined.
6025 void MEDCouplingUMesh::convertDegeneratedCells()
6027 checkFullyDefined();
6028 if(getMeshDimension()<=1)
6029 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
6030 int nbOfCells=getNumberOfCells();
6033 int initMeshLgth=getNodalConnectivityArrayLen();
6034 int *conn=_nodal_connec->getPointer();
6035 int *index=_nodal_connec_index->getPointer();
6039 for(int i=0;i<nbOfCells;i++)
6041 lgthOfCurCell=index[i+1]-posOfCurCell;
6042 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
6044 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
6045 conn+newPos+1,newLgth);
6046 conn[newPos]=newType;
6048 posOfCurCell=index[i+1];
6051 if(newPos!=initMeshLgth)
6052 _nodal_connec->reAlloc(newPos);
6057 * Finds incorrectly oriented cells of this 2D mesh in 3D space.
6058 * A cell is considered to be oriented correctly if an angle between its
6059 * normal vector and a given vector is less than \c PI / \c 2.
6060 * \param [in] vec - 3 components of the vector specifying the correct orientation of
6062 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
6064 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
6065 * is not cleared before filling in.
6066 * \throw If \a this->getMeshDimension() != 2.
6067 * \throw If \a this->getSpaceDimension() != 3.
6069 * \if ENABLE_EXAMPLES
6070 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
6071 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
6074 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<int>& cells) const
6076 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6077 throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
6078 int nbOfCells=getNumberOfCells();
6079 const int *conn=_nodal_connec->getConstPointer();
6080 const int *connI=_nodal_connec_index->getConstPointer();
6081 const double *coordsPtr=_coords->getConstPointer();
6082 for(int i=0;i<nbOfCells;i++)
6084 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6085 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
6087 bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
6088 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6095 * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
6096 * considered to be oriented correctly if an angle between its normal vector and a
6097 * given vector is less than \c PI / \c 2.
6098 * \param [in] vec - 3 components of the vector specifying the correct orientation of
6100 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
6102 * \throw If \a this->getMeshDimension() != 2.
6103 * \throw If \a this->getSpaceDimension() != 3.
6105 * \if ENABLE_EXAMPLES
6106 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
6107 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
6110 * \sa changeOrientationOfCells
6112 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
6114 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6115 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
6116 int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
6117 const int *connI(_nodal_connec_index->getConstPointer());
6118 const double *coordsPtr(_coords->getConstPointer());
6119 bool isModified(false);
6120 for(int i=0;i<nbOfCells;i++)
6122 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6123 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
6125 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6126 bool isQuadratic(cm.isQuadratic());
6127 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6130 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6135 _nodal_connec->declareAsNew();
6140 * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
6142 * \sa orientCorrectly2DCells
6144 void MEDCouplingUMesh::changeOrientationOfCells()
6146 int mdim(getMeshDimension());
6147 if(mdim!=2 && mdim!=1)
6148 throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
6149 int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
6150 const int *connI(_nodal_connec_index->getConstPointer());
6153 for(int i=0;i<nbOfCells;i++)
6155 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6156 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6157 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6162 for(int i=0;i<nbOfCells;i++)
6164 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6165 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6166 cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6172 * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
6173 * oriented facets. The normal vector of the facet should point out of the cell.
6174 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
6175 * is not cleared before filling in.
6176 * \throw If \a this->getMeshDimension() != 3.
6177 * \throw If \a this->getSpaceDimension() != 3.
6178 * \throw If the coordinates array is not set.
6179 * \throw If the nodal connectivity of cells is not defined.
6181 * \if ENABLE_EXAMPLES
6182 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
6183 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
6186 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<int>& cells) const
6188 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6189 throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
6190 int nbOfCells=getNumberOfCells();
6191 const int *conn=_nodal_connec->getConstPointer();
6192 const int *connI=_nodal_connec_index->getConstPointer();
6193 const double *coordsPtr=_coords->getConstPointer();
6194 for(int i=0;i<nbOfCells;i++)
6196 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6197 if(type==INTERP_KERNEL::NORM_POLYHED)
6199 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6206 * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
6208 * \throw If \a this->getMeshDimension() != 3.
6209 * \throw If \a this->getSpaceDimension() != 3.
6210 * \throw If the coordinates array is not set.
6211 * \throw If the nodal connectivity of cells is not defined.
6212 * \throw If the reparation fails.
6214 * \if ENABLE_EXAMPLES
6215 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
6216 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
6218 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
6220 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
6222 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6223 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
6224 int nbOfCells=getNumberOfCells();
6225 int *conn=_nodal_connec->getPointer();
6226 const int *connI=_nodal_connec_index->getConstPointer();
6227 const double *coordsPtr=_coords->getConstPointer();
6228 for(int i=0;i<nbOfCells;i++)
6230 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6231 if(type==INTERP_KERNEL::NORM_POLYHED)
6235 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6236 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
6238 catch(INTERP_KERNEL::Exception& e)
6240 std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
6241 throw INTERP_KERNEL::Exception(oss.str().c_str());
6249 * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
6250 * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
6251 * according to which the first facet of the cell should be oriented to have the normal vector
6252 * pointing out of cell.
6253 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of fixed
6254 * cells. The caller is to delete this array using decrRef() as it is no more
6256 * \throw If \a this->getMeshDimension() != 3.
6257 * \throw If \a this->getSpaceDimension() != 3.
6258 * \throw If the coordinates array is not set.
6259 * \throw If the nodal connectivity of cells is not defined.
6261 * \if ENABLE_EXAMPLES
6262 * \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
6263 * \ref py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
6265 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
6267 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
6269 const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
6270 if(getMeshDimension()!=3)
6271 throw INTERP_KERNEL::Exception(msg);
6272 int spaceDim=getSpaceDimension();
6274 throw INTERP_KERNEL::Exception(msg);
6276 int nbOfCells=getNumberOfCells();
6277 int *conn=_nodal_connec->getPointer();
6278 const int *connI=_nodal_connec_index->getConstPointer();
6279 const double *coo=getCoords()->getConstPointer();
6280 MCAuto<DataArrayInt> cells(DataArrayInt::New()); cells->alloc(0,1);
6281 for(int i=0;i<nbOfCells;i++)
6283 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6284 if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
6286 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
6288 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
6289 cells->pushBackSilent(i);
6293 return cells.retn();
6297 * This method is a faster method to correct orientation of all 3D cells in \a this.
6298 * 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.
6299 * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
6301 * \return a newly allocated int array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
6302 * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
6304 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
6306 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6307 throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
6308 int nbOfCells=getNumberOfCells();
6309 int *conn=_nodal_connec->getPointer();
6310 const int *connI=_nodal_connec_index->getConstPointer();
6311 const double *coordsPtr=_coords->getConstPointer();
6312 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
6313 for(int i=0;i<nbOfCells;i++)
6315 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6318 case INTERP_KERNEL::NORM_TETRA4:
6320 if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6322 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
6323 ret->pushBackSilent(i);
6327 case INTERP_KERNEL::NORM_PYRA5:
6329 if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6331 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
6332 ret->pushBackSilent(i);
6336 case INTERP_KERNEL::NORM_PENTA6:
6337 case INTERP_KERNEL::NORM_HEXA8:
6338 case INTERP_KERNEL::NORM_HEXGP12:
6340 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6342 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
6343 ret->pushBackSilent(i);
6347 case INTERP_KERNEL::NORM_POLYHED:
6349 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6351 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
6352 ret->pushBackSilent(i);
6357 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 !");
6365 * This method has a sense for meshes with spaceDim==3 and meshDim==2.
6366 * If it is not the case an exception will be thrown.
6367 * This method is fast because the first cell of \a this is used to compute the plane.
6368 * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
6369 * \param pos output of size at least 3 used to store a point owned of searched plane.
6371 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
6373 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6374 throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
6375 const int *conn=_nodal_connec->getConstPointer();
6376 const int *connI=_nodal_connec_index->getConstPointer();
6377 const double *coordsPtr=_coords->getConstPointer();
6378 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
6379 std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
6383 * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
6384 * cells. Currently cells of the following types are treated:
6385 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
6386 * For a cell of other type an exception is thrown.
6387 * Space dimension of a 2D mesh can be either 2 or 3.
6388 * The Edge Ratio of a cell \f$t\f$ is:
6389 * \f$\frac{|t|_\infty}{|t|_0}\f$,
6390 * where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
6391 * the smallest edge lengths of \f$t\f$.
6392 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6393 * cells and one time, lying on \a this mesh. The caller is to delete this
6394 * field using decrRef() as it is no more needed.
6395 * \throw If the coordinates array is not set.
6396 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6397 * \throw If the connectivity data array has more than one component.
6398 * \throw If the connectivity data array has a named component.
6399 * \throw If the connectivity index data array has more than one component.
6400 * \throw If the connectivity index data array has a named component.
6401 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
6402 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
6403 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
6405 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
6407 checkConsistencyLight();
6408 int spaceDim=getSpaceDimension();
6409 int meshDim=getMeshDimension();
6410 if(spaceDim!=2 && spaceDim!=3)
6411 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
6412 if(meshDim!=2 && meshDim!=3)
6413 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
6414 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6416 int nbOfCells=getNumberOfCells();
6417 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6418 arr->alloc(nbOfCells,1);
6419 double *pt=arr->getPointer();
6420 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6421 const int *conn=_nodal_connec->getConstPointer();
6422 const int *connI=_nodal_connec_index->getConstPointer();
6423 const double *coo=_coords->getConstPointer();
6425 for(int i=0;i<nbOfCells;i++,pt++)
6427 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6430 case INTERP_KERNEL::NORM_TRI3:
6432 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
6433 *pt=INTERP_KERNEL::triEdgeRatio(tmp);
6436 case INTERP_KERNEL::NORM_QUAD4:
6438 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6439 *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
6442 case INTERP_KERNEL::NORM_TETRA4:
6444 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6445 *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
6449 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
6451 conn+=connI[i+1]-connI[i];
6453 ret->setName("EdgeRatio");
6454 ret->synchronizeTimeWithSupport();
6459 * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
6460 * cells. Currently cells of the following types are treated:
6461 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
6462 * For a cell of other type an exception is thrown.
6463 * Space dimension of a 2D mesh can be either 2 or 3.
6464 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6465 * cells and one time, lying on \a this mesh. The caller is to delete this
6466 * field using decrRef() as it is no more needed.
6467 * \throw If the coordinates array is not set.
6468 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6469 * \throw If the connectivity data array has more than one component.
6470 * \throw If the connectivity data array has a named component.
6471 * \throw If the connectivity index data array has more than one component.
6472 * \throw If the connectivity index data array has a named component.
6473 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
6474 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
6475 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
6477 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
6479 checkConsistencyLight();
6480 int spaceDim=getSpaceDimension();
6481 int meshDim=getMeshDimension();
6482 if(spaceDim!=2 && spaceDim!=3)
6483 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
6484 if(meshDim!=2 && meshDim!=3)
6485 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
6486 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6488 int nbOfCells=getNumberOfCells();
6489 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6490 arr->alloc(nbOfCells,1);
6491 double *pt=arr->getPointer();
6492 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6493 const int *conn=_nodal_connec->getConstPointer();
6494 const int *connI=_nodal_connec_index->getConstPointer();
6495 const double *coo=_coords->getConstPointer();
6497 for(int i=0;i<nbOfCells;i++,pt++)
6499 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6502 case INTERP_KERNEL::NORM_TRI3:
6504 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
6505 *pt=INTERP_KERNEL::triAspectRatio(tmp);
6508 case INTERP_KERNEL::NORM_QUAD4:
6510 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6511 *pt=INTERP_KERNEL::quadAspectRatio(tmp);
6514 case INTERP_KERNEL::NORM_TETRA4:
6516 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6517 *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
6521 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
6523 conn+=connI[i+1]-connI[i];
6525 ret->setName("AspectRatio");
6526 ret->synchronizeTimeWithSupport();
6531 * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
6532 * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
6533 * in 3D space. Currently only cells of the following types are
6534 * treated: INTERP_KERNEL::NORM_QUAD4.
6535 * For a cell of other type an exception is thrown.
6536 * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
6538 * \f$t=\vec{da}\times\vec{ab}\f$,
6539 * \f$u=\vec{ab}\times\vec{bc}\f$
6540 * \f$v=\vec{bc}\times\vec{cd}\f$
6541 * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
6543 * W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
6545 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6546 * cells and one time, lying on \a this mesh. The caller is to delete this
6547 * field using decrRef() as it is no more needed.
6548 * \throw If the coordinates array is not set.
6549 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6550 * \throw If the connectivity data array has more than one component.
6551 * \throw If the connectivity data array has a named component.
6552 * \throw If the connectivity index data array has more than one component.
6553 * \throw If the connectivity index data array has a named component.
6554 * \throw If \a this->getMeshDimension() != 2.
6555 * \throw If \a this->getSpaceDimension() != 3.
6556 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
6558 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
6560 checkConsistencyLight();
6561 int spaceDim=getSpaceDimension();
6562 int meshDim=getMeshDimension();
6564 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
6566 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
6567 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6569 int nbOfCells=getNumberOfCells();
6570 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6571 arr->alloc(nbOfCells,1);
6572 double *pt=arr->getPointer();
6573 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6574 const int *conn=_nodal_connec->getConstPointer();
6575 const int *connI=_nodal_connec_index->getConstPointer();
6576 const double *coo=_coords->getConstPointer();
6578 for(int i=0;i<nbOfCells;i++,pt++)
6580 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6583 case INTERP_KERNEL::NORM_QUAD4:
6585 FillInCompact3DMode(3,4,conn+1,coo,tmp);
6586 *pt=INTERP_KERNEL::quadWarp(tmp);
6590 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
6592 conn+=connI[i+1]-connI[i];
6594 ret->setName("Warp");
6595 ret->synchronizeTimeWithSupport();
6601 * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
6602 * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
6603 * treated: INTERP_KERNEL::NORM_QUAD4.
6604 * The skew is computed as follow for a quad with points (a,b,c,d): let
6605 * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
6606 * then the skew is computed as:
6608 * s=\frac{u}{|u|}\cdot\frac{v}{|v|}
6611 * For a cell of other type an exception is thrown.
6612 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6613 * cells and one time, lying on \a this mesh. The caller is to delete this
6614 * field using decrRef() as it is no more needed.
6615 * \throw If the coordinates array is not set.
6616 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6617 * \throw If the connectivity data array has more than one component.
6618 * \throw If the connectivity data array has a named component.
6619 * \throw If the connectivity index data array has more than one component.
6620 * \throw If the connectivity index data array has a named component.
6621 * \throw If \a this->getMeshDimension() != 2.
6622 * \throw If \a this->getSpaceDimension() != 3.
6623 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
6625 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
6627 checkConsistencyLight();
6628 int spaceDim=getSpaceDimension();
6629 int meshDim=getMeshDimension();
6631 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
6633 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
6634 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6636 int nbOfCells=getNumberOfCells();
6637 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6638 arr->alloc(nbOfCells,1);
6639 double *pt=arr->getPointer();
6640 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6641 const int *conn=_nodal_connec->getConstPointer();
6642 const int *connI=_nodal_connec_index->getConstPointer();
6643 const double *coo=_coords->getConstPointer();
6645 for(int i=0;i<nbOfCells;i++,pt++)
6647 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6650 case INTERP_KERNEL::NORM_QUAD4:
6652 FillInCompact3DMode(3,4,conn+1,coo,tmp);
6653 *pt=INTERP_KERNEL::quadSkew(tmp);
6657 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
6659 conn+=connI[i+1]-connI[i];
6661 ret->setName("Skew");
6662 ret->synchronizeTimeWithSupport();
6667 * 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.
6669 * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
6671 * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
6673 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
6675 checkConsistencyLight();
6676 MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
6678 std::set<INTERP_KERNEL::NormalizedCellType> types;
6679 ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
6680 int spaceDim(getSpaceDimension()),nbCells(getNumberOfCells());
6681 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6682 arr->alloc(nbCells,1);
6683 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
6685 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
6686 MCAuto<DataArrayInt> cellIds(giveCellsWithType(*it));
6687 dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
6690 ret->setName("Diameter");
6695 * This method aggregate the bbox of each cell and put it into bbox parameter.
6697 * \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)
6698 * For all other cases this input parameter is ignored.
6699 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6701 * \throw If \a this is not fully set (coordinates and connectivity).
6702 * \throw If a cell in \a this has no valid nodeId.
6703 * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
6705 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
6707 int mDim(getMeshDimension()),sDim(getSpaceDimension());
6708 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.
6709 return getBoundingBoxForBBTreeFast();
6710 if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
6712 bool presenceOfQuadratic(false);
6713 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
6715 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
6716 if(cm.isQuadratic())
6717 presenceOfQuadratic=true;
6719 if(!presenceOfQuadratic)
6720 return getBoundingBoxForBBTreeFast();
6721 if(mDim==2 && sDim==2)
6722 return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
6724 return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
6726 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) !");
6730 * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
6731 * So meshes having quadratic cells the computed bounding boxes can be invalid !
6733 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6735 * \throw If \a this is not fully set (coordinates and connectivity).
6736 * \throw If a cell in \a this has no valid nodeId.
6738 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
6740 checkFullyDefined();
6741 int spaceDim(getSpaceDimension()),nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
6742 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6743 double *bbox(ret->getPointer());
6744 for(int i=0;i<nbOfCells*spaceDim;i++)
6746 bbox[2*i]=std::numeric_limits<double>::max();
6747 bbox[2*i+1]=-std::numeric_limits<double>::max();
6749 const double *coordsPtr(_coords->getConstPointer());
6750 const int *conn(_nodal_connec->getConstPointer()),*connI(_nodal_connec_index->getConstPointer());
6751 for(int i=0;i<nbOfCells;i++)
6753 int offset=connI[i]+1;
6754 int nbOfNodesForCell(connI[i+1]-offset),kk(0);
6755 for(int j=0;j<nbOfNodesForCell;j++)
6757 int nodeId=conn[offset+j];
6758 if(nodeId>=0 && nodeId<nbOfNodes)
6760 for(int k=0;k<spaceDim;k++)
6762 bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
6763 bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
6770 std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
6771 throw INTERP_KERNEL::Exception(oss.str().c_str());
6778 * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
6779 * useful for 2D meshes having quadratic cells
6780 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
6781 * the two extremities of the arc of circle).
6783 * \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)
6784 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6785 * \throw If \a this is not fully defined.
6786 * \throw If \a this is not a mesh with meshDimension equal to 2.
6787 * \throw If \a this is not a mesh with spaceDimension equal to 2.
6788 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
6790 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
6792 checkFullyDefined();
6793 int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
6794 if(spaceDim!=2 || mDim!=2)
6795 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!");
6796 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6797 double *bbox(ret->getPointer());
6798 const double *coords(_coords->getConstPointer());
6799 const int *conn(_nodal_connec->getConstPointer()),*connI(_nodal_connec_index->getConstPointer());
6800 for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
6802 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
6803 int sz(connI[1]-connI[0]-1);
6804 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=arcDetEps;
6805 std::vector<INTERP_KERNEL::Node *> nodes(sz);
6806 INTERP_KERNEL::QuadraticPolygon *pol(0);
6807 for(int j=0;j<sz;j++)
6809 int nodeId(conn[*connI+1+j]);
6810 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
6812 if(!cm.isQuadratic())
6813 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
6815 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
6816 INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
6817 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
6823 * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
6824 * useful for 2D meshes having quadratic cells
6825 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
6826 * the two extremities of the arc of circle).
6828 * \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)
6829 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6830 * \throw If \a this is not fully defined.
6831 * \throw If \a this is not a mesh with meshDimension equal to 1.
6832 * \throw If \a this is not a mesh with spaceDimension equal to 2.
6833 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
6835 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
6837 checkFullyDefined();
6838 int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
6839 if(spaceDim!=2 || mDim!=1)
6840 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!");
6841 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6842 double *bbox(ret->getPointer());
6843 const double *coords(_coords->getConstPointer());
6844 const int *conn(_nodal_connec->getConstPointer()),*connI(_nodal_connec_index->getConstPointer());
6845 for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
6847 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
6848 int sz(connI[1]-connI[0]-1);
6849 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=arcDetEps;
6850 std::vector<INTERP_KERNEL::Node *> nodes(sz);
6851 INTERP_KERNEL::Edge *edge(0);
6852 for(int j=0;j<sz;j++)
6854 int nodeId(conn[*connI+1+j]);
6855 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
6857 if(!cm.isQuadratic())
6858 edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
6860 edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
6861 const INTERP_KERNEL::Bounds& b(edge->getBounds());
6862 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
6869 namespace MEDCouplingImpl
6874 ConnReader(const int *c, int val):_conn(c),_val(val) { }
6875 bool operator() (const int& pos) { return _conn[pos]!=_val; }
6884 ConnReader2(const int *c, int val):_conn(c),_val(val) { }
6885 bool operator() (const int& pos) { return _conn[pos]==_val; }
6895 * This method expects that \a this is sorted by types. If not an exception will be thrown.
6896 * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
6897 * \a this is composed in cell types.
6898 * The returned array is of size 3*n where n is the number of different types present in \a this.
6899 * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
6900 * This parameter is kept only for compatibility with other methode listed above.
6902 std::vector<int> MEDCouplingUMesh::getDistributionOfTypes() const
6904 checkConnectivityFullyDefined();
6905 const int *conn=_nodal_connec->getConstPointer();
6906 const int *connI=_nodal_connec_index->getConstPointer();
6907 const int *work=connI;
6908 int nbOfCells=getNumberOfCells();
6909 std::size_t n=getAllGeoTypes().size();
6910 std::vector<int> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
6911 std::set<INTERP_KERNEL::NormalizedCellType> types;
6912 for(std::size_t i=0;work!=connI+nbOfCells;i++)
6914 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
6915 if(types.find(typ)!=types.end())
6917 std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
6918 oss << " is not contiguous !";
6919 throw INTERP_KERNEL::Exception(oss.str().c_str());
6923 const int *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
6924 ret[3*i+1]=(int)std::distance(work,work2);
6931 * This method is used to check that this has contiguous cell type in same order than described in \a code.
6932 * only for types cell, type node is not managed.
6933 * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
6934 * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
6935 * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
6936 * If 2 or more same geometric type is in \a code and exception is thrown too.
6938 * This method firstly checks
6939 * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
6940 * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
6941 * an exception is thrown too.
6943 * If all geometric types in \a code are exactly those in \a this null pointer is returned.
6944 * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
6945 * and a DataArrayInt instance is returned that the user has the responsability to deallocate.
6947 DataArrayInt *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<int>& code, const std::vector<const DataArrayInt *>& idsPerType) const
6950 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
6951 std::size_t sz=code.size();
6954 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
6955 std::vector<INTERP_KERNEL::NormalizedCellType> types;
6957 bool isNoPflUsed=true;
6958 for(std::size_t i=0;i<n;i++)
6959 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
6961 types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
6963 if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
6964 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
6965 isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
6968 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
6971 if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
6972 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
6973 if(types.size()==_types.size())
6976 MCAuto<DataArrayInt> ret=DataArrayInt::New();
6978 int *retPtr=ret->getPointer();
6979 const int *connI=_nodal_connec_index->getConstPointer();
6980 const int *conn=_nodal_connec->getConstPointer();
6981 int nbOfCells=getNumberOfCells();
6984 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
6986 i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,(int)(*it)));
6987 int offset=(int)std::distance(connI,i);
6988 const int *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)(*it)));
6989 int nbOfCellsOfCurType=(int)std::distance(i,j);
6990 if(code[3*kk+2]==-1)
6991 for(int k=0;k<nbOfCellsOfCurType;k++)
6995 int idInIdsPerType=code[3*kk+2];
6996 if(idInIdsPerType>=0 && idInIdsPerType<(int)idsPerType.size())
6998 const DataArrayInt *zePfl=idsPerType[idInIdsPerType];
7001 zePfl->checkAllocated();
7002 if(zePfl->getNumberOfComponents()==1)
7004 for(const int *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
7006 if(*k>=0 && *k<nbOfCellsOfCurType)
7007 *retPtr=(*k)+offset;
7010 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
7011 oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
7012 throw INTERP_KERNEL::Exception(oss.str().c_str());
7017 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
7020 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
7024 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
7025 oss << " should be in [0," << idsPerType.size() << ") !";
7026 throw INTERP_KERNEL::Exception(oss.str().c_str());
7035 * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
7036 * 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.
7037 * 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.
7038 * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
7040 * \param [in] profile
7041 * \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.
7042 * \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,
7043 * \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
7044 * \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.
7045 * This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
7046 * \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
7048 void MEDCouplingUMesh::splitProfilePerType(const DataArrayInt *profile, std::vector<int>& code, std::vector<DataArrayInt *>& idsInPflPerType, std::vector<DataArrayInt *>& idsPerType) const
7051 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
7052 if(profile->getNumberOfComponents()!=1)
7053 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
7054 checkConnectivityFullyDefined();
7055 const int *conn=_nodal_connec->getConstPointer();
7056 const int *connI=_nodal_connec_index->getConstPointer();
7057 int nbOfCells=getNumberOfCells();
7058 std::vector<INTERP_KERNEL::NormalizedCellType> types;
7059 std::vector<int> typeRangeVals(1);
7060 for(const int *i=connI;i!=connI+nbOfCells;)
7062 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7063 if(std::find(types.begin(),types.end(),curType)!=types.end())
7065 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
7067 types.push_back(curType);
7068 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7069 typeRangeVals.push_back((int)std::distance(connI,i));
7072 DataArrayInt *castArr=0,*rankInsideCast=0,*castsPresent=0;
7073 profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
7074 MCAuto<DataArrayInt> tmp0=castArr;
7075 MCAuto<DataArrayInt> tmp1=rankInsideCast;
7076 MCAuto<DataArrayInt> tmp2=castsPresent;
7078 int nbOfCastsFinal=castsPresent->getNumberOfTuples();
7079 code.resize(3*nbOfCastsFinal);
7080 std::vector< MCAuto<DataArrayInt> > idsInPflPerType2;
7081 std::vector< MCAuto<DataArrayInt> > idsPerType2;
7082 for(int i=0;i<nbOfCastsFinal;i++)
7084 int castId=castsPresent->getIJ(i,0);
7085 MCAuto<DataArrayInt> tmp3=castArr->findIdsEqual(castId);
7086 idsInPflPerType2.push_back(tmp3);
7087 code[3*i]=(int)types[castId];
7088 code[3*i+1]=tmp3->getNumberOfTuples();
7089 MCAuto<DataArrayInt> tmp4=rankInsideCast->selectByTupleId(tmp3->getConstPointer(),tmp3->getConstPointer()+tmp3->getNumberOfTuples());
7090 if(!tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
7092 tmp4->copyStringInfoFrom(*profile);
7093 idsPerType2.push_back(tmp4);
7094 code[3*i+2]=(int)idsPerType2.size()-1;
7101 std::size_t sz2=idsInPflPerType2.size();
7102 idsInPflPerType.resize(sz2);
7103 for(std::size_t i=0;i<sz2;i++)
7105 DataArrayInt *locDa=idsInPflPerType2[i];
7107 idsInPflPerType[i]=locDa;
7109 std::size_t sz=idsPerType2.size();
7110 idsPerType.resize(sz);
7111 for(std::size_t i=0;i<sz;i++)
7113 DataArrayInt *locDa=idsPerType2[i];
7115 idsPerType[i]=locDa;
7120 * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
7121 * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
7122 * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
7123 * 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.
7125 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *&revDesc, DataArrayInt *&revDescIndx, DataArrayInt *& nM1LevMeshIds, DataArrayInt *&meshnM1Old2New) const
7127 checkFullyDefined();
7128 nM1LevMesh->checkFullyDefined();
7129 if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
7130 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
7131 if(_coords!=nM1LevMesh->getCoords())
7132 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
7133 MCAuto<DataArrayInt> tmp0=DataArrayInt::New();
7134 MCAuto<DataArrayInt> tmp1=DataArrayInt::New();
7135 MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
7136 MCAuto<DataArrayInt> ret0=ret1->sortCellsInMEDFileFrmt();
7137 desc->transformWithIndArr(ret0->getConstPointer(),ret0->getConstPointer()+ret0->getNbOfElems());
7138 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
7139 tmp->setConnectivity(tmp0,tmp1);
7140 tmp->renumberCells(ret0->getConstPointer(),false);
7141 revDesc=tmp->getNodalConnectivity();
7142 revDescIndx=tmp->getNodalConnectivityIndex();
7143 DataArrayInt *ret=0;
7144 if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
7147 ret->getMaxValue(tmp2);
7149 std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
7150 throw INTERP_KERNEL::Exception(oss.str().c_str());
7155 revDescIndx->incrRef();
7158 meshnM1Old2New=ret0;
7163 * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
7164 * necessary for writing the mesh to MED file. Additionally returns a permutation array
7165 * in "Old to New" mode.
7166 * \return DataArrayInt * - a new instance of DataArrayInt. The caller is to delete
7167 * this array using decrRef() as it is no more needed.
7168 * \throw If the nodal connectivity of cells is not defined.
7170 DataArrayInt *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
7172 checkConnectivityFullyDefined();
7173 MCAuto<DataArrayInt> ret=getRenumArrForMEDFileFrmt();
7174 renumberCells(ret->getConstPointer(),false);
7179 * This methods checks that cells are sorted by their types.
7180 * This method makes asumption (no check) that connectivity is correctly set before calling.
7182 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
7184 checkFullyDefined();
7185 const int *conn=_nodal_connec->getConstPointer();
7186 const int *connI=_nodal_connec_index->getConstPointer();
7187 int nbOfCells=getNumberOfCells();
7188 std::set<INTERP_KERNEL::NormalizedCellType> types;
7189 for(const int *i=connI;i!=connI+nbOfCells;)
7191 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7192 if(types.find(curType)!=types.end())
7194 types.insert(curType);
7195 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7201 * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
7202 * The geometric type order is specified by MED file.
7204 * \sa MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
7206 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
7208 return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
7212 * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
7213 * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
7214 * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
7215 * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
7217 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
7219 checkFullyDefined();
7220 const int *conn=_nodal_connec->getConstPointer();
7221 const int *connI=_nodal_connec_index->getConstPointer();
7222 int nbOfCells=getNumberOfCells();
7226 std::set<INTERP_KERNEL::NormalizedCellType> sg;
7227 for(const int *i=connI;i!=connI+nbOfCells;)
7229 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7230 const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
7231 if(isTypeExists!=orderEnd)
7233 int pos=(int)std::distance(orderBg,isTypeExists);
7237 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7241 if(sg.find(curType)==sg.end())
7243 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7254 * This method returns 2 newly allocated DataArrayInt instances. The first is an array of size 'this->getNumberOfCells()' with one component,
7255 * 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
7256 * 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'.
7258 DataArrayInt *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayInt *&nbPerType) const
7260 checkConnectivityFullyDefined();
7261 int nbOfCells=getNumberOfCells();
7262 const int *conn=_nodal_connec->getConstPointer();
7263 const int *connI=_nodal_connec_index->getConstPointer();
7264 MCAuto<DataArrayInt> tmpa=DataArrayInt::New();
7265 MCAuto<DataArrayInt> tmpb=DataArrayInt::New();
7266 tmpa->alloc(nbOfCells,1);
7267 tmpb->alloc((int)std::distance(orderBg,orderEnd),1);
7268 tmpb->fillWithZero();
7269 int *tmp=tmpa->getPointer();
7270 int *tmp2=tmpb->getPointer();
7271 for(const int *i=connI;i!=connI+nbOfCells;i++)
7273 const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
7276 int pos=(int)std::distance(orderBg,where);
7278 tmp[std::distance(connI,i)]=pos;
7282 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
7283 std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
7284 oss << " has a type " << cm.getRepr() << " not in input array of type !";
7285 throw INTERP_KERNEL::Exception(oss.str().c_str());
7288 nbPerType=tmpb.retn();
7293 * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
7295 * \return a new object containing the old to new correspondance.
7297 * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
7299 DataArrayInt *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
7301 return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
7305 * 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.
7306 * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
7307 * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
7308 * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
7310 DataArrayInt *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
7312 DataArrayInt *nbPerType=0;
7313 MCAuto<DataArrayInt> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
7314 nbPerType->decrRef();
7315 return tmpa->buildPermArrPerLevel();
7319 * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
7320 * The number of cells remains unchanged after the call of this method.
7321 * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
7322 * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
7324 * \return the array giving the correspondance old to new.
7326 DataArrayInt *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
7328 checkFullyDefined();
7330 const int *conn=_nodal_connec->getConstPointer();
7331 const int *connI=_nodal_connec_index->getConstPointer();
7332 int nbOfCells=getNumberOfCells();
7333 std::vector<INTERP_KERNEL::NormalizedCellType> types;
7334 for(const int *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
7335 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
7337 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7338 types.push_back(curType);
7339 for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
7341 DataArrayInt *ret=DataArrayInt::New();
7342 ret->alloc(nbOfCells,1);
7343 int *retPtr=ret->getPointer();
7344 std::fill(retPtr,retPtr+nbOfCells,-1);
7346 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
7348 for(const int *i=connI;i!=connI+nbOfCells;i++)
7349 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
7350 retPtr[std::distance(connI,i)]=newCellId++;
7352 renumberCells(retPtr,false);
7357 * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
7358 * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
7359 * This method makes asumption that connectivity is correctly set before calling.
7361 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
7363 checkConnectivityFullyDefined();
7364 const int *conn=_nodal_connec->getConstPointer();
7365 const int *connI=_nodal_connec_index->getConstPointer();
7366 int nbOfCells=getNumberOfCells();
7367 std::vector<MEDCouplingUMesh *> ret;
7368 for(const int *i=connI;i!=connI+nbOfCells;)
7370 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7371 int beginCellId=(int)std::distance(connI,i);
7372 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7373 int endCellId=(int)std::distance(connI,i);
7374 int sz=endCellId-beginCellId;
7375 int *cells=new int[sz];
7376 for(int j=0;j<sz;j++)
7377 cells[j]=beginCellId+j;
7378 MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
7386 * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
7387 * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
7388 * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
7390 * \return a newly allocated instance, that the caller must manage.
7391 * \throw If \a this contains more than one geometric type.
7392 * \throw If the nodal connectivity of \a this is not fully defined.
7393 * \throw If the internal data is not coherent.
7395 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
7397 checkConnectivityFullyDefined();
7398 if(_types.size()!=1)
7399 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7400 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
7401 MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
7402 ret->setCoords(getCoords());
7403 MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
7406 MCAuto<DataArrayInt> c=convertNodalConnectivityToStaticGeoTypeMesh();
7407 retC->setNodalConnectivity(c);
7411 MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
7413 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
7414 DataArrayInt *c=0,*ci=0;
7415 convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
7416 MCAuto<DataArrayInt> cs(c),cis(ci);
7417 retD->setNodalConnectivity(cs,cis);
7422 DataArrayInt *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
7424 checkConnectivityFullyDefined();
7425 if(_types.size()!=1)
7426 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7427 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
7428 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
7431 std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
7432 oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
7433 throw INTERP_KERNEL::Exception(oss.str().c_str());
7435 int nbCells=getNumberOfCells();
7437 int nbNodesPerCell=(int)cm.getNumberOfNodes();
7438 MCAuto<DataArrayInt> connOut=DataArrayInt::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
7439 int *outPtr=connOut->getPointer();
7440 const int *conn=_nodal_connec->begin();
7441 const int *connI=_nodal_connec_index->begin();
7443 for(int i=0;i<nbCells;i++,connI++)
7445 if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
7446 outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
7449 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 << ") !";
7450 throw INTERP_KERNEL::Exception(oss.str().c_str());
7453 return connOut.retn();
7457 * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
7458 * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
7462 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayInt *&nodalConn, DataArrayInt *&nodalConnIndex) const
7464 static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
7465 checkConnectivityFullyDefined();
7466 if(_types.size()!=1)
7467 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7468 int nbCells=getNumberOfCells(),lgth=_nodal_connec->getNumberOfTuples();
7470 throw INTERP_KERNEL::Exception(msg0);
7471 MCAuto<DataArrayInt> c(DataArrayInt::New()),ci(DataArrayInt::New());
7472 c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
7473 int *cp(c->getPointer()),*cip(ci->getPointer());
7474 const int *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
7476 for(int i=0;i<nbCells;i++,cip++,incip++)
7478 int strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
7479 int delta(stop-strt);
7482 if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
7483 cp=std::copy(incp+strt,incp+stop,cp);
7485 throw INTERP_KERNEL::Exception(msg0);
7488 throw INTERP_KERNEL::Exception(msg0);
7489 cip[1]=cip[0]+delta;
7491 nodalConn=c.retn(); nodalConnIndex=ci.retn();
7495 * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
7496 * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
7497 * This method is particulary useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
7498 * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
7499 * are not used here to avoid the build of big permutation array.
7501 * \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
7502 * those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
7503 * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayInt instance whose number of tuples is equal to the number of chunks of same geotype
7504 * in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
7505 * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayInt instance having the same size than \b szOfCellGrpOfSameType. This
7506 * output array gives for each chunck of same type the corresponding mesh id in \b ms.
7507 * \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
7508 * is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
7510 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
7511 DataArrayInt *&szOfCellGrpOfSameType,
7512 DataArrayInt *&idInMsOfCellGrpOfSameType)
7514 std::vector<const MEDCouplingUMesh *> ms2;
7515 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
7518 (*it)->checkConnectivityFullyDefined();
7522 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
7523 const DataArrayDouble *refCoo=ms2[0]->getCoords();
7524 int meshDim=ms2[0]->getMeshDimension();
7525 std::vector<const MEDCouplingUMesh *> m1ssm;
7526 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
7528 std::vector<const MEDCouplingUMesh *> m1ssmSingle;
7529 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
7531 MCAuto<DataArrayInt> ret1(DataArrayInt::New()),ret2(DataArrayInt::New());
7532 ret1->alloc(0,1); ret2->alloc(0,1);
7533 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
7535 if(meshDim!=(*it)->getMeshDimension())
7536 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
7537 if(refCoo!=(*it)->getCoords())
7538 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
7539 std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
7540 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
7541 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
7542 for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
7544 MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
7545 m1ssmSingleAuto.push_back(singleCell);
7546 m1ssmSingle.push_back(singleCell);
7547 ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
7550 MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
7551 MCAuto<DataArrayInt> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
7552 std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
7553 for(std::size_t i=0;i<m1ssm.size();i++)
7554 m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
7555 MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
7556 szOfCellGrpOfSameType=ret1->renumber(renum->getConstPointer());
7557 idInMsOfCellGrpOfSameType=ret2->renumber(renum->getConstPointer());
7562 * This method returns a newly created DataArrayInt instance.
7563 * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
7565 DataArrayInt *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const int *begin, const int *end) const
7567 checkFullyDefined();
7568 const int *conn=_nodal_connec->getConstPointer();
7569 const int *connIndex=_nodal_connec_index->getConstPointer();
7570 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
7571 for(const int *w=begin;w!=end;w++)
7572 if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
7573 ret->pushBackSilent(*w);
7578 * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
7579 * are in [0:getNumberOfCells())
7581 DataArrayInt *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayInt *da) const
7583 checkFullyDefined();
7584 const int *conn=_nodal_connec->getConstPointer();
7585 const int *connI=_nodal_connec_index->getConstPointer();
7586 int nbOfCells=getNumberOfCells();
7587 std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
7588 int *tmp=new int[nbOfCells];
7589 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
7592 for(const int *i=connI;i!=connI+nbOfCells;i++)
7593 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
7594 tmp[std::distance(connI,i)]=j++;
7596 DataArrayInt *ret=DataArrayInt::New();
7597 ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
7598 ret->copyStringInfoFrom(*da);
7599 int *retPtr=ret->getPointer();
7600 const int *daPtr=da->getConstPointer();
7601 int nbOfElems=da->getNbOfElems();
7602 for(int k=0;k<nbOfElems;k++)
7603 retPtr[k]=tmp[daPtr[k]];
7609 * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
7610 * This method \b works \b for mesh sorted by type.
7611 * cells whose ids is in 'idsPerGeoType' array.
7612 * This method conserves coords and name of mesh.
7614 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const int *idsPerGeoTypeBg, const int *idsPerGeoTypeEnd) const
7616 std::vector<int> code=getDistributionOfTypes();
7617 std::size_t nOfTypesInThis=code.size()/3;
7618 int sz=0,szOfType=0;
7619 for(std::size_t i=0;i<nOfTypesInThis;i++)
7624 szOfType=code[3*i+1];
7626 for(const int *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
7627 if(*work<0 || *work>=szOfType)
7629 std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
7630 oss << ". It should be in [0," << szOfType << ") !";
7631 throw INTERP_KERNEL::Exception(oss.str().c_str());
7633 MCAuto<DataArrayInt> idsTokeep=DataArrayInt::New(); idsTokeep->alloc(sz+(int)std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
7634 int *idsPtr=idsTokeep->getPointer();
7636 for(std::size_t i=0;i<nOfTypesInThis;i++)
7639 for(int j=0;j<code[3*i+1];j++)
7642 idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind2nd(std::plus<int>(),offset));
7643 offset+=code[3*i+1];
7645 MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
7646 ret->copyTinyInfoFrom(this);
7651 * This method returns a vector of size 'this->getNumberOfCells()'.
7652 * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
7654 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
7656 int ncell=getNumberOfCells();
7657 std::vector<bool> ret(ncell);
7658 const int *cI=getNodalConnectivityIndex()->getConstPointer();
7659 const int *c=getNodalConnectivity()->getConstPointer();
7660 for(int i=0;i<ncell;i++)
7662 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
7663 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
7664 ret[i]=cm.isQuadratic();
7670 * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
7672 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
7674 if(other->getType()!=UNSTRUCTURED)
7675 throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
7676 const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
7677 return MergeUMeshes(this,otherC);
7681 * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
7682 * computed by averaging coordinates of cell nodes, so this method is not a right
7683 * choice for degnerated meshes (not well oriented, cells with measure close to zero).
7684 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
7685 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
7686 * components. The caller is to delete this array using decrRef() as it is
7688 * \throw If the coordinates array is not set.
7689 * \throw If the nodal connectivity of cells is not defined.
7690 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
7692 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
7694 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
7695 int spaceDim=getSpaceDimension();
7696 int nbOfCells=getNumberOfCells();
7697 ret->alloc(nbOfCells,spaceDim);
7698 ret->copyStringInfoFrom(*getCoords());
7699 double *ptToFill=ret->getPointer();
7700 const int *nodal=_nodal_connec->getConstPointer();
7701 const int *nodalI=_nodal_connec_index->getConstPointer();
7702 const double *coor=_coords->getConstPointer();
7703 for(int i=0;i<nbOfCells;i++)
7705 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
7706 INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
7713 * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
7714 * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
7716 * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
7717 * DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
7719 * \sa MEDCouplingUMesh::computeCellCenterOfMass
7720 * \throw If \a this is not fully defined (coordinates and connectivity)
7721 * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
7723 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
7725 checkFullyDefined();
7726 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
7727 int spaceDim=getSpaceDimension();
7728 int nbOfCells=getNumberOfCells();
7729 int nbOfNodes=getNumberOfNodes();
7730 ret->alloc(nbOfCells,spaceDim);
7731 double *ptToFill=ret->getPointer();
7732 const int *nodal=_nodal_connec->getConstPointer();
7733 const int *nodalI=_nodal_connec_index->getConstPointer();
7734 const double *coor=_coords->getConstPointer();
7735 for(int i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
7737 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
7738 std::fill(ptToFill,ptToFill+spaceDim,0.);
7739 if(type!=INTERP_KERNEL::NORM_POLYHED)
7741 for(const int *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
7743 if(*conn>=0 && *conn<nbOfNodes)
7744 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
7747 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," << nbOfNodes << ") !";
7748 throw INTERP_KERNEL::Exception(oss.str().c_str());
7751 int nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
7752 if(nbOfNodesInCell>0)
7753 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
7756 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
7757 throw INTERP_KERNEL::Exception(oss.str().c_str());
7762 std::set<int> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
7764 for(std::set<int>::const_iterator it=s.begin();it!=s.end();it++)
7766 if(*it>=0 && *it<nbOfNodes)
7767 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
7770 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," << nbOfNodes << ") !";
7771 throw INTERP_KERNEL::Exception(oss.str().c_str());
7775 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)s.size()));
7778 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
7779 throw INTERP_KERNEL::Exception(oss.str().c_str());
7787 * Returns a new DataArrayDouble holding barycenters of specified cells. The
7788 * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
7789 * are specified via an array of cell ids.
7790 * \warning Validity of the specified cell ids is not checked!
7791 * Valid range is [ 0, \a this->getNumberOfCells() ).
7792 * \param [in] begin - an array of cell ids of interest.
7793 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
7794 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
7795 * end - \a begin ) tuples per \a this->getSpaceDimension() components. The
7796 * caller is to delete this array using decrRef() as it is no more needed.
7797 * \throw If the coordinates array is not set.
7798 * \throw If the nodal connectivity of cells is not defined.
7800 * \if ENABLE_EXAMPLES
7801 * \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
7802 * \ref py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
7805 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const int *begin, const int *end) const
7807 DataArrayDouble *ret=DataArrayDouble::New();
7808 int spaceDim=getSpaceDimension();
7809 int nbOfTuple=(int)std::distance(begin,end);
7810 ret->alloc(nbOfTuple,spaceDim);
7811 double *ptToFill=ret->getPointer();
7812 double *tmp=new double[spaceDim];
7813 const int *nodal=_nodal_connec->getConstPointer();
7814 const int *nodalI=_nodal_connec_index->getConstPointer();
7815 const double *coor=_coords->getConstPointer();
7816 for(const int *w=begin;w!=end;w++)
7818 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
7819 INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
7827 * 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".
7828 * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
7829 * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
7830 * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
7831 * This method is useful to detect 2D cells in 3D space that are not coplanar.
7833 * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
7834 * \throw If spaceDim!=3 or meshDim!=2.
7835 * \throw If connectivity of \a this is invalid.
7836 * \throw If connectivity of a cell in \a this points to an invalid node.
7838 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
7840 MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
7841 int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
7842 if(getSpaceDimension()!=3 || getMeshDimension()!=2)
7843 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
7844 ret->alloc(nbOfCells,4);
7845 double *retPtr(ret->getPointer());
7846 const int *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
7847 const double *coor(_coords->begin());
7848 for(int i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
7850 double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
7851 if(nodalI[1]-nodalI[0]>=3)
7853 for(int j=0;j<3;j++)
7855 int nodeId(nodal[nodalI[0]+1+j]);
7856 if(nodeId>=0 && nodeId<nbOfNodes)
7857 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
7860 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
7861 throw INTERP_KERNEL::Exception(oss.str().c_str());
7867 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
7868 throw INTERP_KERNEL::Exception(oss.str().c_str());
7870 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
7871 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
7877 * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
7880 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
7883 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
7884 da->checkAllocated();
7885 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(da->getName(),0);
7887 int nbOfTuples=da->getNumberOfTuples();
7888 MCAuto<DataArrayInt> c=DataArrayInt::New();
7889 MCAuto<DataArrayInt> cI=DataArrayInt::New();
7890 c->alloc(2*nbOfTuples,1);
7891 cI->alloc(nbOfTuples+1,1);
7892 int *cp=c->getPointer();
7893 int *cip=cI->getPointer();
7895 for(int i=0;i<nbOfTuples;i++)
7897 *cp++=INTERP_KERNEL::NORM_POINT1;
7901 ret->setConnectivity(c,cI,true);
7905 * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
7906 * Cells and nodes of
7907 * the first mesh precede cells and nodes of the second mesh within the result mesh.
7908 * \param [in] mesh1 - the first mesh.
7909 * \param [in] mesh2 - the second mesh.
7910 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7911 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7912 * is no more needed.
7913 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
7914 * \throw If the coordinates array is not set in none of the meshes.
7915 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
7916 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
7918 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
7920 std::vector<const MEDCouplingUMesh *> tmp(2);
7921 tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
7922 return MergeUMeshes(tmp);
7926 * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
7927 * Cells and nodes of
7928 * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
7929 * \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
7930 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7931 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7932 * is no more needed.
7933 * \throw If \a a.size() == 0.
7934 * \throw If \a a[ *i* ] == NULL.
7935 * \throw If the coordinates array is not set in none of the meshes.
7936 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
7937 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
7939 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(std::vector<const MEDCouplingUMesh *>& a)
7941 std::size_t sz=a.size();
7943 return MergeUMeshesLL(a);
7944 for(std::size_t ii=0;ii<sz;ii++)
7947 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
7948 throw INTERP_KERNEL::Exception(oss.str().c_str());
7950 std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
7951 std::vector< const MEDCouplingUMesh * > aa(sz);
7953 for(std::size_t i=0;i<sz && spaceDim==-3;i++)
7955 const MEDCouplingUMesh *cur=a[i];
7956 const DataArrayDouble *coo=cur->getCoords();
7958 spaceDim=coo->getNumberOfComponents();
7961 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
7962 for(std::size_t i=0;i<sz;i++)
7964 bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
7967 return MergeUMeshesLL(aa);
7972 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesLL(std::vector<const MEDCouplingUMesh *>& a)
7975 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : input array must be NON EMPTY !");
7976 std::vector<const MEDCouplingUMesh *>::const_iterator it=a.begin();
7977 int meshDim=(*it)->getMeshDimension();
7978 int nbOfCells=(*it)->getNumberOfCells();
7979 int meshLgth=(*it++)->getNodalConnectivityArrayLen();
7980 for(;it!=a.end();it++)
7982 if(meshDim!=(*it)->getMeshDimension())
7983 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, MergeUMeshes impossible !");
7984 nbOfCells+=(*it)->getNumberOfCells();
7985 meshLgth+=(*it)->getNodalConnectivityArrayLen();
7987 std::vector<const MEDCouplingPointSet *> aps(a.size());
7988 std::copy(a.begin(),a.end(),aps.begin());
7989 MCAuto<DataArrayDouble> pts=MergeNodesArray(aps);
7990 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("merge",meshDim);
7991 ret->setCoords(pts);
7992 MCAuto<DataArrayInt> c=DataArrayInt::New();
7993 c->alloc(meshLgth,1);
7994 int *cPtr=c->getPointer();
7995 MCAuto<DataArrayInt> cI=DataArrayInt::New();
7996 cI->alloc(nbOfCells+1,1);
7997 int *cIPtr=cI->getPointer();
8001 for(it=a.begin();it!=a.end();it++)
8003 int curNbOfCell=(*it)->getNumberOfCells();
8004 const int *curCI=(*it)->_nodal_connec_index->getConstPointer();
8005 const int *curC=(*it)->_nodal_connec->getConstPointer();
8006 cIPtr=std::transform(curCI+1,curCI+curNbOfCell+1,cIPtr,std::bind2nd(std::plus<int>(),offset));
8007 for(int j=0;j<curNbOfCell;j++)
8009 const int *src=curC+curCI[j];
8011 for(;src!=curC+curCI[j+1];src++,cPtr++)
8019 offset+=curCI[curNbOfCell];
8020 offset2+=(*it)->getNumberOfNodes();
8023 ret->setConnectivity(c,cI,true);
8030 * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
8031 * dimension and sharing the node coordinates array.
8032 * All cells of the first mesh precede all cells of the second mesh
8033 * within the result mesh.
8034 * \param [in] mesh1 - the first mesh.
8035 * \param [in] mesh2 - the second mesh.
8036 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8037 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8038 * is no more needed.
8039 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
8040 * \throw If the meshes do not share the node coordinates array.
8041 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
8042 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
8044 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
8046 std::vector<const MEDCouplingUMesh *> tmp(2);
8047 tmp[0]=mesh1; tmp[1]=mesh2;
8048 return MergeUMeshesOnSameCoords(tmp);
8052 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
8053 * dimension and sharing the node coordinates array.
8054 * All cells of the *i*-th mesh precede all cells of the
8055 * (*i*+1)-th mesh within the result mesh.
8056 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
8057 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8058 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8059 * is no more needed.
8060 * \throw If \a a.size() == 0.
8061 * \throw If \a a[ *i* ] == NULL.
8062 * \throw If the meshes do not share the node coordinates array.
8063 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
8064 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
8066 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
8069 throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
8070 for(std::size_t ii=0;ii<meshes.size();ii++)
8073 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
8074 throw INTERP_KERNEL::Exception(oss.str().c_str());
8076 const DataArrayDouble *coords=meshes.front()->getCoords();
8077 int meshDim=meshes.front()->getMeshDimension();
8078 std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
8080 int meshIndexLgth=0;
8081 for(;iter!=meshes.end();iter++)
8083 if(coords!=(*iter)->getCoords())
8084 throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
8085 if(meshDim!=(*iter)->getMeshDimension())
8086 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
8087 meshLgth+=(*iter)->getNodalConnectivityArrayLen();
8088 meshIndexLgth+=(*iter)->getNumberOfCells();
8090 MCAuto<DataArrayInt> nodal=DataArrayInt::New();
8091 nodal->alloc(meshLgth,1);
8092 int *nodalPtr=nodal->getPointer();
8093 MCAuto<DataArrayInt> nodalIndex=DataArrayInt::New();
8094 nodalIndex->alloc(meshIndexLgth+1,1);
8095 int *nodalIndexPtr=nodalIndex->getPointer();
8097 for(iter=meshes.begin();iter!=meshes.end();iter++)
8099 const int *nod=(*iter)->getNodalConnectivity()->getConstPointer();
8100 const int *index=(*iter)->getNodalConnectivityIndex()->getConstPointer();
8101 int nbOfCells=(*iter)->getNumberOfCells();
8102 int meshLgth2=(*iter)->getNodalConnectivityArrayLen();
8103 nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
8104 if(iter!=meshes.begin())
8105 nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind2nd(std::plus<int>(),offset));
8107 nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
8110 MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
8111 ret->setName("merge");
8112 ret->setMeshDimension(meshDim);
8113 ret->setConnectivity(nodal,nodalIndex,true);
8114 ret->setCoords(coords);
8119 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
8120 * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
8121 * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
8122 * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
8123 * New" mode are returned for each input mesh.
8124 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
8125 * \param [in] compType - specifies a cell comparison technique. For meaning of its
8126 * valid values [0,1,2], see zipConnectivityTraducer().
8127 * \param [in,out] corr - an array of DataArrayInt, of the same size as \a
8128 * meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
8129 * mesh. The caller is to delete each of the arrays using decrRef() as it is
8131 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8132 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8133 * is no more needed.
8134 * \throw If \a meshes.size() == 0.
8135 * \throw If \a meshes[ *i* ] == NULL.
8136 * \throw If the meshes do not share the node coordinates array.
8137 * \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
8138 * \throw If the \a meshes are of different dimension (getMeshDimension()).
8139 * \throw If the nodal connectivity of cells of any of \a meshes is not defined.
8140 * \throw If the nodal connectivity any of \a meshes includes an invalid id.
8142 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayInt *>& corr)
8144 //All checks are delegated to MergeUMeshesOnSameCoords
8145 MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
8146 MCAuto<DataArrayInt> o2n=ret->zipConnectivityTraducer(compType);
8147 corr.resize(meshes.size());
8148 std::size_t nbOfMeshes=meshes.size();
8150 const int *o2nPtr=o2n->getConstPointer();
8151 for(std::size_t i=0;i<nbOfMeshes;i++)
8153 DataArrayInt *tmp=DataArrayInt::New();
8154 int curNbOfCells=meshes[i]->getNumberOfCells();
8155 tmp->alloc(curNbOfCells,1);
8156 std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
8157 offset+=curNbOfCells;
8158 tmp->setName(meshes[i]->getName());
8165 * Makes all given meshes share the nodal connectivity array. The common connectivity
8166 * array is created by concatenating the connectivity arrays of all given meshes. All
8167 * the given meshes must be of the same space dimension but dimension of cells **can
8168 * differ**. This method is particulary useful in MEDLoader context to build a \ref
8169 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
8170 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
8171 * \param [in,out] meshes - a vector of meshes to update.
8172 * \throw If any of \a meshes is NULL.
8173 * \throw If the coordinates array is not set in any of \a meshes.
8174 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
8175 * \throw If \a meshes are of different space dimension.
8177 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
8179 std::size_t sz=meshes.size();
8182 std::vector< const DataArrayDouble * > coords(meshes.size());
8183 std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
8184 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
8188 (*it)->checkConnectivityFullyDefined();
8189 const DataArrayDouble *coo=(*it)->getCoords();
8194 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
8195 oss << " has no coordinate array defined !";
8196 throw INTERP_KERNEL::Exception(oss.str().c_str());
8201 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
8202 oss << " is null !";
8203 throw INTERP_KERNEL::Exception(oss.str().c_str());
8206 MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
8207 std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
8208 int offset=(*it)->getNumberOfNodes();
8209 (*it++)->setCoords(res);
8210 for(;it!=meshes.end();it++)
8212 int oldNumberOfNodes=(*it)->getNumberOfNodes();
8213 (*it)->setCoords(res);
8214 (*it)->shiftNodeNumbersInConn(offset);
8215 offset+=oldNumberOfNodes;
8220 * Merges nodes coincident with a given precision within all given meshes that share
8221 * the nodal connectivity array. The given meshes **can be of different** mesh
8222 * dimension. This method is particulary useful in MEDLoader context to build a \ref
8223 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
8224 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
8225 * \param [in,out] meshes - a vector of meshes to update.
8226 * \param [in] eps - the precision used to detect coincident nodes (infinite norm).
8227 * \throw If any of \a meshes is NULL.
8228 * \throw If the \a meshes do not share the same node coordinates array.
8229 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
8231 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
8235 std::set<const DataArrayDouble *> s;
8236 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
8239 s.insert((*it)->getCoords());
8242 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 !";
8243 throw INTERP_KERNEL::Exception(oss.str().c_str());
8248 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 !";
8249 throw INTERP_KERNEL::Exception(oss.str().c_str());
8251 const DataArrayDouble *coo=*(s.begin());
8255 DataArrayInt *comm,*commI;
8256 coo->findCommonTuples(eps,-1,comm,commI);
8257 MCAuto<DataArrayInt> tmp1(comm),tmp2(commI);
8258 int oldNbOfNodes=coo->getNumberOfTuples();
8260 MCAuto<DataArrayInt> o2n=DataArrayInt::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
8261 if(oldNbOfNodes==newNbOfNodes)
8263 MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->getConstPointer(),newNbOfNodes);
8264 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
8266 (*it)->renumberNodesInConn(o2n->getConstPointer());
8267 (*it)->setCoords(newCoords);
8272 * 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.
8273 * \param nbOfNodesPerLev in parameter that specifies the number of nodes of one slice of global dataset
8274 * \param isQuad specifies the policy of connectivity.
8275 * @ret in/out parameter in which the result will be append
8277 void MEDCouplingUMesh::AppendExtrudedCell(const int *connBg, const int *connEnd, int nbOfNodesPerLev, bool isQuad, std::vector<int>& ret)
8279 INTERP_KERNEL::NormalizedCellType flatType=(INTERP_KERNEL::NormalizedCellType)connBg[0];
8280 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(flatType);
8281 ret.push_back(cm.getExtrudedType());
8282 int deltaz=isQuad?2*nbOfNodesPerLev:nbOfNodesPerLev;
8285 case INTERP_KERNEL::NORM_POINT1:
8287 ret.push_back(connBg[1]);
8288 ret.push_back(connBg[1]+nbOfNodesPerLev);
8291 case INTERP_KERNEL::NORM_SEG2:
8293 int conn[4]={connBg[1],connBg[2],connBg[2]+deltaz,connBg[1]+deltaz};
8294 ret.insert(ret.end(),conn,conn+4);
8297 case INTERP_KERNEL::NORM_SEG3:
8299 int conn[8]={connBg[1],connBg[3],connBg[3]+deltaz,connBg[1]+deltaz,connBg[2],connBg[3]+nbOfNodesPerLev,connBg[2]+deltaz,connBg[1]+nbOfNodesPerLev};
8300 ret.insert(ret.end(),conn,conn+8);
8303 case INTERP_KERNEL::NORM_QUAD4:
8305 int conn[8]={connBg[1],connBg[2],connBg[3],connBg[4],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4]+deltaz};
8306 ret.insert(ret.end(),conn,conn+8);
8309 case INTERP_KERNEL::NORM_TRI3:
8311 int conn[6]={connBg[1],connBg[2],connBg[3],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz};
8312 ret.insert(ret.end(),conn,conn+6);
8315 case INTERP_KERNEL::NORM_TRI6:
8317 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,
8318 connBg[1]+nbOfNodesPerLev,connBg[2]+nbOfNodesPerLev,connBg[3]+nbOfNodesPerLev};
8319 ret.insert(ret.end(),conn,conn+15);
8322 case INTERP_KERNEL::NORM_QUAD8:
8325 connBg[1],connBg[2],connBg[3],connBg[4],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4]+deltaz,
8326 connBg[5],connBg[6],connBg[7],connBg[8],connBg[5]+deltaz,connBg[6]+deltaz,connBg[7]+deltaz,connBg[8]+deltaz,
8327 connBg[1]+nbOfNodesPerLev,connBg[2]+nbOfNodesPerLev,connBg[3]+nbOfNodesPerLev,connBg[4]+nbOfNodesPerLev
8329 ret.insert(ret.end(),conn,conn+20);
8332 case INTERP_KERNEL::NORM_POLYGON:
8334 std::back_insert_iterator< std::vector<int> > ii(ret);
8335 std::copy(connBg+1,connEnd,ii);
8337 std::reverse_iterator<const int *> rConnBg(connEnd);
8338 std::reverse_iterator<const int *> rConnEnd(connBg+1);
8339 std::transform(rConnBg,rConnEnd,ii,std::bind2nd(std::plus<int>(),deltaz));
8340 std::size_t nbOfRadFaces=std::distance(connBg+1,connEnd);
8341 for(std::size_t i=0;i<nbOfRadFaces;i++)
8344 int conn[4]={connBg[(i+1)%nbOfRadFaces+1],connBg[i+1],connBg[i+1]+deltaz,connBg[(i+1)%nbOfRadFaces+1]+deltaz};
8345 std::copy(conn,conn+4,ii);
8350 throw INTERP_KERNEL::Exception("A flat type has been detected that has not its extruded representation !");
8355 * This static operates only for coords in 3D. The polygon is specfied by its connectivity nodes in [ \a begin , \a end ).
8357 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const int *begin, const int *end, const double *coords)
8360 double v[3]={0.,0.,0.};
8361 std::size_t sz=std::distance(begin,end);
8366 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];
8367 v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
8368 v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
8370 double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
8372 // Try using quadratic points if standard points are degenerated (for example a QPOLYG with two
8373 // SEG3 forming a circle):
8374 if (fabs(ret) < INTERP_KERNEL::DEFAULT_ABS_TOL && isQuadratic)
8376 v[0] = 0.0; v[1] = 0.0; v[2] = 0.0;
8377 for(std::size_t j=0;j<sz;j++)
8379 if (j%2) // current point i is quadratic, next point i+1 is standard
8382 ip1 = (j+1)%sz; // ip1 = "i+1"
8384 else // current point i is standard, next point i+1 is quadratic
8389 v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
8390 v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
8391 v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
8393 ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
8399 * The polyhedron is specfied by its connectivity nodes in [ \a begin , \a end ).
8401 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const int *begin, const int *end, const double *coords)
8403 std::vector<std::pair<int,int> > edges;
8404 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
8405 const int *bgFace=begin;
8406 for(std::size_t i=0;i<nbOfFaces;i++)
8408 const int *endFace=std::find(bgFace+1,end,-1);
8409 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
8410 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8412 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8413 if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
8415 edges.push_back(p1);
8419 return INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)>-EPS_FOR_POLYH_ORIENTATION;
8423 * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
8425 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const int *begin, const int *end, const double *coords)
8427 double vec0[3],vec1[3];
8428 std::size_t sz=std::distance(begin,end);
8430 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
8431 int nbOfNodes=(int)sz/2;
8432 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
8433 const double *pt0=coords+3*begin[0];
8434 const double *pt1=coords+3*begin[nbOfNodes];
8435 vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
8436 return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
8439 void MEDCouplingUMesh::CorrectExtrudedStaticCell(int *begin, int *end)
8441 std::size_t sz=std::distance(begin,end);
8442 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
8443 std::size_t nbOfNodes(sz/2);
8444 std::copy(begin,end,(int *)tmp);
8445 for(std::size_t j=1;j<nbOfNodes;j++)
8447 begin[j]=tmp[nbOfNodes-j];
8448 begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
8452 bool MEDCouplingUMesh::IsTetra4WellOriented(const int *begin, const int *end, const double *coords)
8454 std::size_t sz=std::distance(begin,end);
8456 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
8457 double vec0[3],vec1[3];
8458 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
8459 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];
8460 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;
8463 bool MEDCouplingUMesh::IsPyra5WellOriented(const int *begin, const int *end, const double *coords)
8465 std::size_t sz=std::distance(begin,end);
8467 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
8469 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
8470 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
8471 return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
8475 * 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 )
8476 * 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
8479 * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
8480 * \param [in] coords the coordinates with nb of components exactly equal to 3
8481 * \param [in] begin begin of the nodal connectivity (geometric type included) of a single polyhedron cell
8482 * \param [in] end end of nodal connectivity of a single polyhedron cell (excluded)
8483 * \param [out] res the result is put at the end of the vector without any alteration of the data.
8485 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, const int *begin, const int *end, DataArrayInt *res)
8487 int nbFaces=std::count(begin+1,end,-1)+1;
8488 MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
8489 double *vPtr=v->getPointer();
8490 MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,1);
8491 double *pPtr=p->getPointer();
8492 const int *stFaceConn=begin+1;
8493 for(int i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
8495 const int *endFaceConn=std::find(stFaceConn,end,-1);
8496 ComputeVecAndPtOfFace(eps,coords->getConstPointer(),stFaceConn,endFaceConn,vPtr,pPtr);
8497 stFaceConn=endFaceConn+1;
8499 pPtr=p->getPointer(); vPtr=v->getPointer();
8500 DataArrayInt *comm1=0,*commI1=0;
8501 v->findCommonTuples(eps,-1,comm1,commI1);
8502 MCAuto<DataArrayInt> comm1Auto(comm1),commI1Auto(commI1);
8503 const int *comm1Ptr=comm1->getConstPointer();
8504 const int *commI1Ptr=commI1->getConstPointer();
8505 int nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
8506 res->pushBackSilent((int)INTERP_KERNEL::NORM_POLYHED);
8508 MCAuto<MEDCouplingUMesh> mm=MEDCouplingUMesh::New("",3);
8509 mm->setCoords(const_cast<DataArrayDouble *>(coords)); mm->allocateCells(1); mm->insertNextCell(INTERP_KERNEL::NORM_POLYHED,(int)std::distance(begin+1,end),begin+1);
8510 mm->finishInsertingCells();
8512 for(int i=0;i<nbOfGrps1;i++)
8514 int vecId=comm1Ptr[commI1Ptr[i]];
8515 MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
8516 DataArrayInt *comm2=0,*commI2=0;
8517 tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
8518 MCAuto<DataArrayInt> comm2Auto(comm2),commI2Auto(commI2);
8519 const int *comm2Ptr=comm2->getConstPointer();
8520 const int *commI2Ptr=commI2->getConstPointer();
8521 int nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
8522 for(int j=0;j<nbOfGrps2;j++)
8524 if(commI2Ptr[j+1]-commI2Ptr[j]<=1)
8526 res->insertAtTheEnd(begin,end);
8527 res->pushBackSilent(-1);
8531 int pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
8532 MCAuto<DataArrayInt> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
8533 ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
8534 DataArrayInt *tmp0=DataArrayInt::New(),*tmp1=DataArrayInt::New(),*tmp2=DataArrayInt::New(),*tmp3=DataArrayInt::New();
8535 MCAuto<MEDCouplingUMesh> mm2=mm->buildDescendingConnectivity(tmp0,tmp1,tmp2,tmp3); tmp0->decrRef(); tmp1->decrRef(); tmp2->decrRef(); tmp3->decrRef();
8536 MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(mm2->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
8537 MCAuto<DataArrayInt> idsNodeTmp=mm3->zipCoordsTraducer();
8538 MCAuto<DataArrayInt> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
8539 const int *idsNodePtr=idsNode->getConstPointer();
8540 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];
8541 double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
8542 double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
8543 if(std::abs(norm)>eps)
8545 double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
8546 mm3->rotate(center,vec,angle);
8548 mm3->changeSpaceDimension(2);
8549 MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
8550 const int *conn4=mm4->getNodalConnectivity()->getConstPointer();
8551 const int *connI4=mm4->getNodalConnectivityIndex()->getConstPointer();
8552 int nbOfCells=mm4->getNumberOfCells();
8553 for(int k=0;k<nbOfCells;k++)
8556 for(const int *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
8557 res->pushBackSilent(idsNodePtr[*work]);
8558 res->pushBackSilent(-1);
8563 res->popBackSilent();
8567 * 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
8568 * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
8570 * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
8571 * \param [in] coords coordinates expected to have 3 components.
8572 * \param [in] begin start of the nodal connectivity of the face.
8573 * \param [in] end end of the nodal connectivity (excluded) of the face.
8574 * \param [out] v the normalized vector of size 3
8575 * \param [out] p the pos of plane
8577 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const int *begin, const int *end, double *v, double *p)
8579 std::size_t nbPoints=std::distance(begin,end);
8581 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
8582 double vec[3]={0.,0.,0.};
8584 bool refFound=false;
8585 for(;j<nbPoints-1 && !refFound;j++)
8587 vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
8588 vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
8589 vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
8590 double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
8594 vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
8597 for(std::size_t i=j;i<nbPoints-1;i++)
8600 curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
8601 curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
8602 curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
8603 double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
8606 curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
8607 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];
8608 norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
8611 v[0]/=norm; v[1]/=norm; v[2]/=norm;
8612 *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
8616 throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
8620 * This method tries to obtain a well oriented polyhedron.
8621 * If the algorithm fails, an exception will be thrown.
8623 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(int *begin, int *end, const double *coords)
8625 std::list< std::pair<int,int> > edgesOK,edgesFinished;
8626 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
8627 std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
8629 int *bgFace=begin,*endFace=std::find(begin+1,end,-1);
8630 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
8631 for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<int,int> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
8633 while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
8636 std::size_t smthChanged=0;
8637 for(std::size_t i=0;i<nbOfFaces;i++)
8639 endFace=std::find(bgFace+1,end,-1);
8640 nbOfEdgesInFace=std::distance(bgFace,endFace);
8644 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8646 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8647 std::pair<int,int> p2(p1.second,p1.first);
8648 bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
8649 bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
8650 if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
8655 std::reverse(bgFace+1,endFace);
8656 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8658 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8659 std::pair<int,int> p2(p1.second,p1.first);
8660 if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
8661 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str().c_str()); }
8662 if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
8663 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str().c_str()); }
8664 std::list< std::pair<int,int> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
8665 if(it!=edgesOK.end())
8668 edgesFinished.push_back(p1);
8671 edgesOK.push_back(p1);
8678 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
8680 if(!edgesOK.empty())
8681 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
8682 if(INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)<-EPS_FOR_POLYH_ORIENTATION)
8683 {//not lucky ! The first face was not correctly oriented : reorient all faces...
8685 for(std::size_t i=0;i<nbOfFaces;i++)
8687 endFace=std::find(bgFace+1,end,-1);
8688 std::reverse(bgFace+1,endFace);
8694 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMeshLinear(const MEDCouplingUMesh *skin, const DataArrayInt *n2o) const
8696 int nbOfNodesExpected(skin->getNumberOfNodes());
8697 const int *n2oPtr(n2o->getConstPointer());
8698 MCAuto<DataArrayInt> revNodal(DataArrayInt::New()),revNodalI(DataArrayInt::New());
8699 skin->getReverseNodalConnectivity(revNodal,revNodalI);
8700 const int *revNodalPtr(revNodal->getConstPointer()),*revNodalIPtr(revNodalI->getConstPointer());
8701 const int *nodalPtr(skin->getNodalConnectivity()->getConstPointer());
8702 const int *nodalIPtr(skin->getNodalConnectivityIndex()->getConstPointer());
8703 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfNodesExpected+1,1);
8704 int *work(ret->getPointer()); *work++=INTERP_KERNEL::NORM_POLYGON;
8705 if(nbOfNodesExpected<1)
8707 int prevCell(0),prevNode(nodalPtr[nodalIPtr[0]+1]);
8708 *work++=n2oPtr[prevNode];
8709 for(int i=1;i<nbOfNodesExpected;i++)
8711 if(nodalIPtr[prevCell+1]-nodalIPtr[prevCell]==3)
8713 std::set<int> conn(nodalPtr+nodalIPtr[prevCell]+1,nodalPtr+nodalIPtr[prevCell]+3);
8714 conn.erase(prevNode);
8717 int curNode(*(conn.begin()));
8718 *work++=n2oPtr[curNode];
8719 std::set<int> shar(revNodalPtr+revNodalIPtr[curNode],revNodalPtr+revNodalIPtr[curNode+1]);
8720 shar.erase(prevCell);
8723 prevCell=*(shar.begin());
8727 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected 2 !");
8730 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected 1 !");
8733 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected cell !");
8738 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMeshQuadratic(const MEDCouplingUMesh *skin, const DataArrayInt *n2o) const
8740 int nbOfNodesExpected(skin->getNumberOfNodes());
8741 int nbOfTurn(nbOfNodesExpected/2);
8742 const int *n2oPtr(n2o->getConstPointer());
8743 MCAuto<DataArrayInt> revNodal(DataArrayInt::New()),revNodalI(DataArrayInt::New());
8744 skin->getReverseNodalConnectivity(revNodal,revNodalI);
8745 const int *revNodalPtr(revNodal->getConstPointer()),*revNodalIPtr(revNodalI->getConstPointer());
8746 const int *nodalPtr(skin->getNodalConnectivity()->getConstPointer());
8747 const int *nodalIPtr(skin->getNodalConnectivityIndex()->getConstPointer());
8748 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfNodesExpected+1,1);
8749 int *work(ret->getPointer()); *work++=INTERP_KERNEL::NORM_QPOLYG;
8750 if(nbOfNodesExpected<1)
8752 int prevCell(0),prevNode(nodalPtr[nodalIPtr[0]+1]);
8753 *work=n2oPtr[prevNode]; work[nbOfTurn]=n2oPtr[nodalPtr[nodalIPtr[0]+3]]; work++;
8754 for(int i=1;i<nbOfTurn;i++)
8756 if(nodalIPtr[prevCell+1]-nodalIPtr[prevCell]==4)
8758 std::set<int> conn(nodalPtr+nodalIPtr[prevCell]+1,nodalPtr+nodalIPtr[prevCell]+3);
8759 conn.erase(prevNode);
8762 int curNode(*(conn.begin()));
8763 *work=n2oPtr[curNode];
8764 std::set<int> shar(revNodalPtr+revNodalIPtr[curNode],revNodalPtr+revNodalIPtr[curNode+1]);
8765 shar.erase(prevCell);
8768 int curCell(*(shar.begin()));
8769 work[nbOfTurn]=n2oPtr[nodalPtr[nodalIPtr[curCell]+3]];
8775 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected 2 !");
8778 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected 1 !");
8781 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected cell !");
8787 * This method makes the assumption spacedimension == meshdimension == 2.
8788 * This method works only for linear cells.
8790 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
8792 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMesh() const
8794 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
8795 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
8796 MCAuto<MEDCouplingUMesh> skin(computeSkin());
8797 int oldNbOfNodes(skin->getNumberOfNodes());
8798 MCAuto<DataArrayInt> o2n(skin->zipCoordsTraducer());
8799 int nbOfNodesExpected(skin->getNumberOfNodes());
8800 MCAuto<DataArrayInt> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
8801 int nbCells(skin->getNumberOfCells());
8802 if(nbCells==nbOfNodesExpected)
8803 return buildUnionOf2DMeshLinear(skin,n2o);
8804 else if(2*nbCells==nbOfNodesExpected)
8805 return buildUnionOf2DMeshQuadratic(skin,n2o);
8807 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
8811 * This method makes the assumption spacedimension == meshdimension == 3.
8812 * This method works only for linear cells.
8814 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
8816 DataArrayInt *MEDCouplingUMesh::buildUnionOf3DMesh() const
8818 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8819 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
8820 MCAuto<MEDCouplingUMesh> m=computeSkin();
8821 const int *conn=m->getNodalConnectivity()->getConstPointer();
8822 const int *connI=m->getNodalConnectivityIndex()->getConstPointer();
8823 int nbOfCells=m->getNumberOfCells();
8824 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
8825 int *work=ret->getPointer(); *work++=INTERP_KERNEL::NORM_POLYHED;
8828 work=std::copy(conn+connI[0]+1,conn+connI[1],work);
8829 for(int i=1;i<nbOfCells;i++)
8832 work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
8838 * \brief Creates a graph of cell neighbors
8839 * \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
8840 * In the sky line array, graph arcs are stored in terms of (index,value) notation.
8842 * - index: 0 3 5 6 6
8843 * - value: 1 2 3 2 3 3
8844 * means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
8845 * Arcs are not doubled but reflexive (1,1) arcs are present for each cell
8847 MEDCouplingSkyLineArray *MEDCouplingUMesh::generateGraph() const
8849 checkConnectivityFullyDefined();
8851 int meshDim = this->getMeshDimension();
8852 MEDCoupling::DataArrayInt* indexr=MEDCoupling::DataArrayInt::New();
8853 MEDCoupling::DataArrayInt* revConn=MEDCoupling::DataArrayInt::New();
8854 this->getReverseNodalConnectivity(revConn,indexr);
8855 const int* indexr_ptr=indexr->getConstPointer();
8856 const int* revConn_ptr=revConn->getConstPointer();
8858 const MEDCoupling::DataArrayInt* index;
8859 const MEDCoupling::DataArrayInt* conn;
8860 conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
8861 index=this->getNodalConnectivityIndex();
8862 int nbCells=this->getNumberOfCells();
8863 const int* index_ptr=index->getConstPointer();
8864 const int* conn_ptr=conn->getConstPointer();
8866 //creating graph arcs (cell to cell relations)
8867 //arcs are stored in terms of (index,value) notation
8870 // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
8871 // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
8873 //warning here one node have less than or equal effective number of cell with it
8874 //but cell could have more than effective nodes
8875 //because other equals nodes in other domain (with other global inode)
8876 std::vector <int> cell2cell_index(nbCells+1,0);
8877 std::vector <int> cell2cell;
8878 cell2cell.reserve(3*nbCells);
8880 for (int icell=0; icell<nbCells;icell++)
8882 std::map<int,int > counter;
8883 for (int iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
8885 int inode=conn_ptr[iconn];
8886 for (int iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
8888 int icell2=revConn_ptr[iconnr];
8889 std::map<int,int>::iterator iter=counter.find(icell2);
8890 if (iter!=counter.end()) (iter->second)++;
8891 else counter.insert(std::make_pair(icell2,1));
8894 for (std::map<int,int>::const_iterator iter=counter.begin();
8895 iter!=counter.end(); iter++)
8896 if (iter->second >= meshDim)
8898 cell2cell_index[icell+1]++;
8899 cell2cell.push_back(iter->first);
8904 cell2cell_index[0]=0;
8905 for (int icell=0; icell<nbCells;icell++)
8906 cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
8908 //filling up index and value to create skylinearray structure
8909 MEDCouplingSkyLineArray* array=new MEDCouplingSkyLineArray(cell2cell_index,cell2cell);
8914 * This method put in zip format into parameter 'zipFrmt' in full interlace mode.
8915 * This format is often asked by INTERP_KERNEL algorithms to avoid many indirections into coordinates array.
8917 void MEDCouplingUMesh::FillInCompact3DMode(int spaceDim, int nbOfNodesInCell, const int *conn, const double *coo, double *zipFrmt)
8921 for(int i=0;i<nbOfNodesInCell;i++)
8922 w=std::copy(coo+3*conn[i],coo+3*conn[i]+3,w);
8923 else if(spaceDim==2)
8925 for(int i=0;i<nbOfNodesInCell;i++)
8927 w=std::copy(coo+2*conn[i],coo+2*conn[i]+2,w);
8932 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::FillInCompact3DMode : Invalid spaceDim specified : must be 2 or 3 !");
8935 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
8937 int nbOfCells=getNumberOfCells();
8939 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
8940 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};
8941 ofs << " <" << getVTKDataSetType() << ">\n";
8942 ofs << " <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
8943 ofs << " <PointData>\n" << pointData << std::endl;
8944 ofs << " </PointData>\n";
8945 ofs << " <CellData>\n" << cellData << std::endl;
8946 ofs << " </CellData>\n";
8947 ofs << " <Points>\n";
8948 if(getSpaceDimension()==3)
8949 _coords->writeVTK(ofs,8,"Points",byteData);
8952 MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
8953 coo->writeVTK(ofs,8,"Points",byteData);
8955 ofs << " </Points>\n";
8956 ofs << " <Cells>\n";
8957 const int *cPtr=_nodal_connec->getConstPointer();
8958 const int *cIPtr=_nodal_connec_index->getConstPointer();
8959 MCAuto<DataArrayInt> faceoffsets=DataArrayInt::New(); faceoffsets->alloc(nbOfCells,1);
8960 MCAuto<DataArrayInt> types=DataArrayInt::New(); types->alloc(nbOfCells,1);
8961 MCAuto<DataArrayInt> offsets=DataArrayInt::New(); offsets->alloc(nbOfCells,1);
8962 MCAuto<DataArrayInt> connectivity=DataArrayInt::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
8963 int *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
8964 int szFaceOffsets=0,szConn=0;
8965 for(int i=0;i<nbOfCells;i++,w1++,w2++,w3++)
8968 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
8971 *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
8972 w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
8976 int deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
8977 *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
8978 std::set<int> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
8979 *w3=szConn+(int)c.size(); szConn+=(int)c.size();
8980 w4=std::copy(c.begin(),c.end(),w4);
8983 types->transformWithIndArr(PARAMEDMEM2VTKTYPETRADUCER,PARAMEDMEM2VTKTYPETRADUCER+INTERP_KERNEL::NORM_MAXTYPE+1);
8984 types->writeVTK(ofs,8,"UInt8","types",byteData);
8985 offsets->writeVTK(ofs,8,"Int32","offsets",byteData);
8986 if(szFaceOffsets!=0)
8987 {//presence of Polyhedra
8988 connectivity->reAlloc(szConn);
8989 faceoffsets->writeVTK(ofs,8,"Int32","faceoffsets",byteData);
8990 MCAuto<DataArrayInt> faces=DataArrayInt::New(); faces->alloc(szFaceOffsets,1);
8991 w1=faces->getPointer();
8992 for(int i=0;i<nbOfCells;i++)
8993 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
8995 int nbFaces=std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1)+1;
8997 const int *w6=cPtr+cIPtr[i]+1,*w5=0;
8998 for(int j=0;j<nbFaces;j++)
9000 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
9001 *w1++=(int)std::distance(w6,w5);
9002 w1=std::copy(w6,w5,w1);
9006 faces->writeVTK(ofs,8,"Int32","faces",byteData);
9008 connectivity->writeVTK(ofs,8,"Int32","connectivity",byteData);
9009 ofs << " </Cells>\n";
9010 ofs << " </Piece>\n";
9011 ofs << " </" << getVTKDataSetType() << ">\n";
9014 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
9016 stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
9018 { stream << " Not set !"; return ; }
9019 stream << " Mesh dimension : " << _mesh_dim << ".";
9023 { stream << " No coordinates set !"; return ; }
9024 if(!_coords->isAllocated())
9025 { stream << " Coordinates set but not allocated !"; return ; }
9026 stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
9027 stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
9028 if(!_nodal_connec_index)
9029 { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
9030 if(!_nodal_connec_index->isAllocated())
9031 { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
9032 int lgth=_nodal_connec_index->getNumberOfTuples();
9033 int cpt=_nodal_connec_index->getNumberOfComponents();
9034 if(cpt!=1 || lgth<1)
9036 stream << std::endl << "Number of cells : " << lgth-1 << ".";
9039 std::string MEDCouplingUMesh::getVTKDataSetType() const
9041 return std::string("UnstructuredGrid");
9044 std::string MEDCouplingUMesh::getVTKFileExtension() const
9046 return std::string("vtu");
9050 * Partitions the first given 2D mesh using the second given 2D mesh as a tool, and
9051 * returns a result mesh constituted by polygons.
9052 * Thus the final result contains all nodes from m1 plus new nodes. However it doesn't necessarily contains
9053 * all nodes from m2.
9054 * The meshes should be in 2D space. In
9055 * addition, returns two arrays mapping cells of the result mesh to cells of the input
9057 * \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
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] 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
9060 * 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)
9061 * \param [in] eps - precision used to detect coincident mesh entities.
9062 * \param [out] cellNb1 - a new instance of DataArrayInt holding for each result
9063 * cell an id of the cell of \a m1 it comes from. The caller is to delete
9064 * this array using decrRef() as it is no more needed.
9065 * \param [out] cellNb2 - a new instance of DataArrayInt holding for each result
9066 * cell an id of the cell of \a m2 it comes from. -1 value means that a
9067 * result cell comes from a cell (or part of cell) of \a m1 not overlapped by
9068 * any cell of \a m2. The caller is to delete this array using decrRef() as
9069 * it is no more needed.
9070 * \return MEDCouplingUMesh * - the result 2D mesh which is a new instance of
9071 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
9072 * is no more needed.
9073 * \throw If the coordinates array is not set in any of the meshes.
9074 * \throw If the nodal connectivity of cells is not defined in any of the meshes.
9075 * \throw If any of the meshes is not a 2D mesh in 2D space.
9077 * \sa conformize2D, mergeNodes
9079 MEDCouplingUMesh *MEDCouplingUMesh::Intersect2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2,
9080 double eps, DataArrayInt *&cellNb1, DataArrayInt *&cellNb2)
9083 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshes : input meshes must be not NULL !");
9084 m1->checkFullyDefined();
9085 m2->checkFullyDefined();
9086 if(m1->getMeshDimension()!=2 || m1->getSpaceDimension()!=2 || m2->getMeshDimension()!=2 || m2->getSpaceDimension()!=2)
9087 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshes works on umeshes m1 AND m2 with meshdim equal to 2 and spaceDim equal to 2 too!");
9089 // Step 1: compute all edge intersections (new nodes)
9090 std::vector< std::vector<int> > intersectEdge1, colinear2, subDiv2;
9091 MEDCouplingUMesh *m1Desc=0,*m2Desc=0; // descending connec. meshes
9092 DataArrayInt *desc1=0,*descIndx1=0,*revDesc1=0,*revDescIndx1=0,*desc2=0,*descIndx2=0,*revDesc2=0,*revDescIndx2=0;
9093 std::vector<double> addCoo,addCoordsQuadratic; // coordinates of newly created nodes
9094 IntersectDescending2DMeshes(m1,m2,eps,intersectEdge1,colinear2, subDiv2,
9095 m1Desc,desc1,descIndx1,revDesc1,revDescIndx1,
9096 addCoo, m2Desc,desc2,descIndx2,revDesc2,revDescIndx2);
9097 revDesc1->decrRef(); revDescIndx1->decrRef(); revDesc2->decrRef(); revDescIndx2->decrRef();
9098 MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(desc2),dd4(descIndx2);
9099 MCAuto<MEDCouplingUMesh> dd5(m1Desc),dd6(m2Desc);
9101 // Step 2: re-order newly created nodes according to the ordering found in m2
9102 std::vector< std::vector<int> > intersectEdge2;
9103 BuildIntersectEdges(m1Desc,m2Desc,addCoo,subDiv2,intersectEdge2);
9104 subDiv2.clear(); dd5=0; dd6=0;
9107 std::vector<int> cr,crI; //no DataArrayInt because interface with Geometric2D
9108 std::vector<int> cNb1,cNb2; //no DataArrayInt because interface with Geometric2D
9109 BuildIntersecting2DCellsFromEdges(eps,m1,desc1->getConstPointer(),descIndx1->getConstPointer(),intersectEdge1,colinear2,m2,desc2->getConstPointer(),descIndx2->getConstPointer(),intersectEdge2,addCoo,
9110 /* outputs -> */addCoordsQuadratic,cr,crI,cNb1,cNb2);
9112 // Step 4: Prepare final result:
9113 MCAuto<DataArrayDouble> addCooDa(DataArrayDouble::New());
9114 addCooDa->alloc((int)(addCoo.size())/2,2);
9115 std::copy(addCoo.begin(),addCoo.end(),addCooDa->getPointer());
9116 MCAuto<DataArrayDouble> addCoordsQuadraticDa(DataArrayDouble::New());
9117 addCoordsQuadraticDa->alloc((int)(addCoordsQuadratic.size())/2,2);
9118 std::copy(addCoordsQuadratic.begin(),addCoordsQuadratic.end(),addCoordsQuadraticDa->getPointer());
9119 std::vector<const DataArrayDouble *> coordss(4);
9120 coordss[0]=m1->getCoords(); coordss[1]=m2->getCoords(); coordss[2]=addCooDa; coordss[3]=addCoordsQuadraticDa;
9121 MCAuto<DataArrayDouble> coo(DataArrayDouble::Aggregate(coordss));
9122 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("Intersect2D",2));
9123 MCAuto<DataArrayInt> conn(DataArrayInt::New()); conn->alloc((int)cr.size(),1); std::copy(cr.begin(),cr.end(),conn->getPointer());
9124 MCAuto<DataArrayInt> connI(DataArrayInt::New()); connI->alloc((int)crI.size(),1); std::copy(crI.begin(),crI.end(),connI->getPointer());
9125 MCAuto<DataArrayInt> c1(DataArrayInt::New()); c1->alloc((int)cNb1.size(),1); std::copy(cNb1.begin(),cNb1.end(),c1->getPointer());
9126 MCAuto<DataArrayInt> c2(DataArrayInt::New()); c2->alloc((int)cNb2.size(),1); std::copy(cNb2.begin(),cNb2.end(),c2->getPointer());
9127 ret->setConnectivity(conn,connI,true);
9128 ret->setCoords(coo);
9129 cellNb1=c1.retn(); cellNb2=c2.retn();
9135 bool IsColinearOfACellOf(const std::vector< std::vector<int> >& intersectEdge1, const std::vector<int>& candidates, int start, int stop, int& retVal)
9137 if(candidates.empty())
9139 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
9141 const std::vector<int>& pool(intersectEdge1[*it]);
9142 int tmp[2]; tmp[0]=start; tmp[1]=stop;
9143 if(std::search(pool.begin(),pool.end(),tmp,tmp+2)!=pool.end())
9148 tmp[0]=stop; tmp[1]=start;
9149 if(std::search(pool.begin(),pool.end(),tmp,tmp+2)!=pool.end())
9158 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,
9159 MCAuto<DataArrayInt>& idsInRetColinear, MCAuto<DataArrayInt>& idsInMesh1DForIdsInRetColinear)
9161 idsInRetColinear=DataArrayInt::New(); idsInRetColinear->alloc(0,1);
9162 idsInMesh1DForIdsInRetColinear=DataArrayInt::New(); idsInMesh1DForIdsInRetColinear->alloc(0,1);
9163 int nCells(mesh1D->getNumberOfCells());
9164 if(nCells!=(int)intersectEdge2.size())
9165 throw INTERP_KERNEL::Exception("BuildMesh1DCutFrom : internal error # 1 !");
9166 const DataArrayDouble *coo2(mesh1D->getCoords());
9167 const int *c(mesh1D->getNodalConnectivity()->begin()),*ci(mesh1D->getNodalConnectivityIndex()->begin());
9168 const double *coo2Ptr(coo2->begin());
9169 int offset1(coords1->getNumberOfTuples());
9170 int offset2(offset1+coo2->getNumberOfTuples());
9171 int offset3(offset2+addCoo.size()/2);
9172 std::vector<double> addCooQuad;
9173 MCAuto<DataArrayInt> cOut(DataArrayInt::New()),ciOut(DataArrayInt::New()); cOut->alloc(0,1); ciOut->alloc(1,1); ciOut->setIJ(0,0,0);
9174 int tmp[4],cicnt(0),kk(0);
9175 for(int i=0;i<nCells;i++)
9177 std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
9178 INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coo2Ptr,m));
9179 const std::vector<int>& subEdges(intersectEdge2[i]);
9180 int nbSubEdge(subEdges.size()/2);
9181 for(int j=0;j<nbSubEdge;j++,kk++)
9183 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));
9184 MCAuto<INTERP_KERNEL::Edge> e2(e->buildEdgeLyingOnMe(n1,n2));
9185 INTERP_KERNEL::Edge *e2Ptr(e2);
9186 std::map<int,int>::const_iterator itm;
9187 if(dynamic_cast<INTERP_KERNEL::EdgeArcCircle *>(e2Ptr))
9189 tmp[0]=INTERP_KERNEL::NORM_SEG3;
9190 itm=mergedNodes.find(subEdges[2*j]);
9191 tmp[1]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j];
9192 itm=mergedNodes.find(subEdges[2*j+1]);
9193 tmp[2]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j+1];
9194 tmp[3]=offset3+(int)addCooQuad.size()/2;
9196 e2->getBarycenter(tmp2); addCooQuad.insert(addCooQuad.end(),tmp2,tmp2+2);
9198 cOut->insertAtTheEnd(tmp,tmp+4);
9199 ciOut->pushBackSilent(cicnt);
9203 tmp[0]=INTERP_KERNEL::NORM_SEG2;
9204 itm=mergedNodes.find(subEdges[2*j]);
9205 tmp[1]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j];
9206 itm=mergedNodes.find(subEdges[2*j+1]);
9207 tmp[2]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j+1];
9209 cOut->insertAtTheEnd(tmp,tmp+3);
9210 ciOut->pushBackSilent(cicnt);
9213 if(IsColinearOfACellOf(intersectEdge1,colinear2[i],tmp[1],tmp[2],tmp00))
9215 idsInRetColinear->pushBackSilent(kk);
9216 idsInMesh1DForIdsInRetColinear->pushBackSilent(tmp00);
9221 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(mesh1D->getName(),1));
9222 ret->setConnectivity(cOut,ciOut,true);
9223 MCAuto<DataArrayDouble> arr3(DataArrayDouble::New());
9224 arr3->useArray(&addCoo[0],false,C_DEALLOC,(int)addCoo.size()/2,2);
9225 MCAuto<DataArrayDouble> arr4(DataArrayDouble::New()); arr4->useArray(&addCooQuad[0],false,C_DEALLOC,(int)addCooQuad.size()/2,2);
9226 std::vector<const DataArrayDouble *> coordss(4);
9227 coordss[0]=coords1; coordss[1]=mesh1D->getCoords(); coordss[2]=arr3; coordss[3]=arr4;
9228 MCAuto<DataArrayDouble> arr(DataArrayDouble::Aggregate(coordss));
9229 ret->setCoords(arr);
9233 MEDCouplingUMesh *BuildRefined2DCellLinear(const DataArrayDouble *coords, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9235 std::vector<int> allEdges;
9236 for(const int *it2(descBg);it2!=descEnd;it2++)
9238 const std::vector<int>& edge1(intersectEdge1[std::abs(*it2)-1]);
9240 allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9242 allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9244 std::size_t nb(allEdges.size());
9246 throw INTERP_KERNEL::Exception("BuildRefined2DCellLinear : internal error 1 !");
9247 std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9248 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
9249 ret->setCoords(coords);
9250 ret->allocateCells(1);
9251 std::vector<int> connOut(nbOfEdgesOf2DCellSplit);
9252 for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9253 connOut[kk]=allEdges[2*kk];
9254 ret->insertNextCell(INTERP_KERNEL::NORM_POLYGON,connOut.size(),&connOut[0]);
9258 MEDCouplingUMesh *BuildRefined2DCellQuadratic(const DataArrayDouble *coords, const MEDCouplingUMesh *mesh2D, int cellIdInMesh2D, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9260 const int *c(mesh2D->getNodalConnectivity()->begin()),*ci(mesh2D->getNodalConnectivityIndex()->begin());
9261 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[cellIdInMesh2D]]));
9263 unsigned sz(cm.getNumberOfSons2(c+ci[cellIdInMesh2D]+1,ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]-1));
9264 if(sz!=std::distance(descBg,descEnd))
9265 throw INTERP_KERNEL::Exception("BuildRefined2DCellQuadratic : internal error 1 !");
9266 INTERP_KERNEL::AutoPtr<int> tmpPtr(new int[ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]]);
9267 std::vector<int> allEdges,centers;
9268 const double *coordsPtr(coords->begin());
9269 MCAuto<DataArrayDouble> addCoo(DataArrayDouble::New()); addCoo->alloc(0,1);
9270 int offset(coords->getNumberOfTuples());
9271 for(const int *it2(descBg);it2!=descEnd;it2++,ii++)
9273 INTERP_KERNEL::NormalizedCellType typeOfSon;
9274 cm.fillSonCellNodalConnectivity2(ii,c+ci[cellIdInMesh2D]+1,ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]-1,tmpPtr,typeOfSon);
9275 const std::vector<int>& edge1(intersectEdge1[std::abs(*it2)-1]);
9277 allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9279 allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9281 centers.push_back(tmpPtr[2]);//special case where no subsplit of edge -> reuse the original center.
9283 {//the current edge has been subsplit -> create corresponding centers.
9284 std::size_t nbOfCentersToAppend(edge1.size()/2);
9285 std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9286 MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpPtr,coordsPtr,m));
9287 std::vector<int>::const_iterator it3(allEdges.end()-edge1.size());
9288 for(std::size_t k=0;k<nbOfCentersToAppend;k++)
9291 const double *aa(coordsPtr+2*(*it3++));
9292 const double *bb(coordsPtr+2*(*it3++));
9293 ee->getMiddleOfPoints(aa,bb,tmpp);
9294 addCoo->insertAtTheEnd(tmpp,tmpp+2);
9295 centers.push_back(offset+k);
9299 std::size_t nb(allEdges.size());
9301 throw INTERP_KERNEL::Exception("BuildRefined2DCellQuadratic : internal error 2 !");
9302 std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9303 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
9305 ret->setCoords(coords);
9308 addCoo->rearrange(2);
9309 addCoo=DataArrayDouble::Aggregate(coords,addCoo);
9310 ret->setCoords(addCoo);
9312 ret->allocateCells(1);
9313 std::vector<int> connOut(nbOfEdgesOf2DCellSplit);
9314 for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9315 connOut[kk]=allEdges[2*kk];
9316 connOut.insert(connOut.end(),centers.begin(),centers.end());
9317 ret->insertNextCell(INTERP_KERNEL::NORM_QPOLYG,connOut.size(),&connOut[0]);
9322 * This method creates a refinement of a cell in \a mesh2D. Those cell is defined by descending connectivity and the sorted subdivided nodal connectivity
9325 * \param [in] mesh2D - The origin 2D mesh. \b Warning \b coords are not those of \a mesh2D. But mesh2D->getCoords()==coords[:mesh2D->getNumberOfNodes()]
9327 MEDCouplingUMesh *BuildRefined2DCell(const DataArrayDouble *coords, const MEDCouplingUMesh *mesh2D, int cellIdInMesh2D, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9329 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(mesh2D->getTypeOfCell(cellIdInMesh2D)));
9330 if(!cm.isQuadratic())
9331 return BuildRefined2DCellLinear(coords,descBg,descEnd,intersectEdge1);
9333 return BuildRefined2DCellQuadratic(coords,mesh2D,cellIdInMesh2D,descBg,descEnd,intersectEdge1);
9336 void AddCellInMesh2D(MEDCouplingUMesh *mesh2D, const std::vector<int>& conn, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edges)
9339 for(std::vector< MCAuto<INTERP_KERNEL::Edge> >::const_iterator it=edges.begin();it!=edges.end();it++)
9341 const INTERP_KERNEL::Edge *ee(*it);
9342 if(dynamic_cast<const INTERP_KERNEL::EdgeArcCircle *>(ee))
9346 mesh2D->insertNextCell(INTERP_KERNEL::NORM_POLYGON,conn.size(),&conn[0]);
9349 const double *coo(mesh2D->getCoords()->begin());
9350 std::size_t sz(conn.size());
9351 std::vector<double> addCoo;
9352 std::vector<int> conn2(conn);
9353 int offset(mesh2D->getNumberOfNodes());
9354 for(std::size_t i=0;i<sz;i++)
9357 edges[(i+1)%sz]->getMiddleOfPoints(coo+2*conn[i],coo+2*conn[(i+1)%sz],tmp);// tony a chier i+1 -> i
9358 addCoo.insert(addCoo.end(),tmp,tmp+2);
9359 conn2.push_back(offset+(int)i);
9361 mesh2D->getCoords()->rearrange(1);
9362 mesh2D->getCoords()->pushBackValsSilent(&addCoo[0],&addCoo[0]+addCoo.size());
9363 mesh2D->getCoords()->rearrange(2);
9364 mesh2D->insertNextCell(INTERP_KERNEL::NORM_QPOLYG,conn2.size(),&conn2[0]);
9369 * \b WARNING edges in out1 coming from \a splitMesh1D are \b NOT oriented because only used for equation of curve.
9371 * This method cuts in 2 parts the input 2D cell given using boundaries description (\a edge1Bis and \a edge1BisPtr) using
9372 * a set of edges defined in \a splitMesh1D.
9374 void BuildMesh2DCutInternal2(const MEDCouplingUMesh *splitMesh1D, const std::vector<int>& edge1Bis, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edge1BisPtr,
9375 std::vector< std::vector<int> >& out0, std::vector< std::vector< MCAuto<INTERP_KERNEL::Edge> > >& out1)
9377 std::size_t nb(edge1Bis.size()/2);
9378 std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9379 int iEnd(splitMesh1D->getNumberOfCells());
9381 throw INTERP_KERNEL::Exception("BuildMesh2DCutInternal2 : internal error ! input 1D mesh must have at least one cell !");
9383 const int *cSplitPtr(splitMesh1D->getNodalConnectivity()->begin()),*ciSplitPtr(splitMesh1D->getNodalConnectivityIndex()->begin());
9384 for(ii=0;ii<nb && edge1Bis[2*ii]!=cSplitPtr[ciSplitPtr[0]+1];ii++);
9385 for(jj=ii;jj<nb && edge1Bis[2*jj+1]!=cSplitPtr[ciSplitPtr[iEnd-1]+2];jj++);
9388 {//the edges splitMesh1D[iStart:iEnd] does not fully cut the current 2D cell -> single output cell
9389 out0.resize(1); out1.resize(1);
9390 std::vector<int>& connOut(out0[0]);
9391 connOut.resize(nbOfEdgesOf2DCellSplit);
9392 std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr(out1[0]);
9393 edgesPtr.resize(nbOfEdgesOf2DCellSplit);
9394 for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9396 connOut[kk]=edge1Bis[2*kk];
9397 edgesPtr[kk]=edge1BisPtr[2*kk];
9402 // [i,iEnd[ contains the
9403 out0.resize(2); out1.resize(2);
9404 std::vector<int>& connOutLeft(out0[0]);
9405 std::vector<int>& connOutRight(out0[1]);//connOutLeft should end with edge1Bis[2*ii] and connOutRight should end with edge1Bis[2*jj+1]
9406 std::vector< MCAuto<INTERP_KERNEL::Edge> >& eleft(out1[0]);
9407 std::vector< MCAuto<INTERP_KERNEL::Edge> >& eright(out1[1]);
9408 for(std::size_t k=ii;k<jj+1;k++)
9409 { connOutLeft.push_back(edge1Bis[2*k+1]); eleft.push_back(edge1BisPtr[2*k+1]); }
9410 std::vector< MCAuto<INTERP_KERNEL::Edge> > ees(iEnd);
9411 for(int ik=0;ik<iEnd;ik++)
9413 std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9414 MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)cSplitPtr[ciSplitPtr[ik]],cSplitPtr+ciSplitPtr[ik]+1,splitMesh1D->getCoords()->begin(),m));
9417 for(int ik=iEnd-1;ik>=0;ik--)
9418 connOutLeft.push_back(cSplitPtr[ciSplitPtr[ik]+1]);
9419 for(std::size_t k=jj+1;k<nbOfEdgesOf2DCellSplit+ii;k++)
9420 { connOutRight.push_back(edge1Bis[2*k+1]); eright.push_back(edge1BisPtr[2*k+1]); }
9421 eleft.insert(eleft.end(),ees.rbegin(),ees.rend());
9422 for(int ik=0;ik<iEnd;ik++)
9423 connOutRight.push_back(cSplitPtr[ciSplitPtr[ik]+2]);
9424 eright.insert(eright.end(),ees.begin(),ees.end());
9436 CellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr);
9438 std::vector<int> _edges;
9439 std::vector< MCAuto<INTERP_KERNEL::Edge> > _edges_ptr;
9442 CellInfo::CellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr)
9444 std::size_t nbe(edges.size());
9445 std::vector<int> edges2(2*nbe); std::vector< MCAuto<INTERP_KERNEL::Edge> > edgesPtr2(2*nbe);
9446 for(std::size_t i=0;i<nbe;i++)
9448 edges2[2*i]=edges[i]; edges2[2*i+1]=edges[(i+1)%nbe];
9449 edgesPtr2[2*i]=edgesPtr[(i+1)%nbe]; edgesPtr2[2*i+1]=edgesPtr[(i+1)%nbe];//tony a chier
9451 _edges.resize(4*nbe); _edges_ptr.resize(4*nbe);
9452 std::copy(edges2.begin(),edges2.end(),_edges.begin()); std::copy(edges2.begin(),edges2.end(),_edges.begin()+2*nbe);
9453 std::copy(edgesPtr2.begin(),edgesPtr2.end(),_edges_ptr.begin()); std::copy(edgesPtr2.begin(),edgesPtr2.end(),_edges_ptr.begin()+2*nbe);
9459 EdgeInfo(int istart, int iend, const MCAuto<MEDCouplingUMesh>& mesh):_istart(istart),_iend(iend),_mesh(mesh),_left(-7),_right(-7) { }
9460 EdgeInfo(int istart, int iend, int pos, const MCAuto<INTERP_KERNEL::Edge>& edge):_istart(istart),_iend(iend),_edge(edge),_left(pos),_right(pos+1) { }
9461 bool isInMyRange(int pos) const { return pos>=_istart && pos<_iend; }
9462 void somethingHappendAt(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight);
9463 void feedEdgeInfoAt(double eps, const MEDCouplingUMesh *mesh2D, int offset, int neighbors[2]) const;
9467 MCAuto<MEDCouplingUMesh> _mesh;
9468 MCAuto<INTERP_KERNEL::Edge> _edge;
9473 void EdgeInfo::somethingHappendAt(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight)
9475 const MEDCouplingUMesh *mesh(_mesh);
9481 { _left++; _right++; return ; }
9484 bool isLeft(std::find(newLeft.begin(),newLeft.end(),_edge)!=newLeft.end()),isRight(std::find(newRight.begin(),newRight.end(),_edge)!=newRight.end());
9485 if((isLeft && isRight) || (!isLeft && !isRight))
9486 throw INTERP_KERNEL::Exception("EdgeInfo::somethingHappendAt : internal error # 1 !");
9497 bool isLeft(std::find(newLeft.begin(),newLeft.end(),_edge)!=newLeft.end()),isRight(std::find(newRight.begin(),newRight.end(),_edge)!=newRight.end());
9498 if((isLeft && isRight) || (!isLeft && !isRight))
9499 throw INTERP_KERNEL::Exception("EdgeInfo::somethingHappendAt : internal error # 2 !");
9514 void EdgeInfo::feedEdgeInfoAt(double eps, const MEDCouplingUMesh *mesh2D, int offset, int neighbors[2]) const
9516 const MEDCouplingUMesh *mesh(_mesh);
9519 neighbors[0]=offset+_left; neighbors[1]=offset+_right;
9522 {// not fully splitting cell case
9523 if(mesh2D->getNumberOfCells()==1)
9524 {//little optimization. 1 cell no need to find in which cell mesh is !
9525 neighbors[0]=offset; neighbors[1]=offset;
9530 MCAuto<DataArrayDouble> barys(mesh->computeCellCenterOfMass());
9531 int cellId(mesh2D->getCellContainingPoint(barys->begin(),eps));
9533 throw INTERP_KERNEL::Exception("EdgeInfo::feedEdgeInfoAt : internal error !");
9534 neighbors[0]=offset+cellId; neighbors[1]=offset+cellId;
9539 class VectorOfCellInfo
9542 VectorOfCellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr);
9543 std::size_t size() const { return _pool.size(); }
9544 int getPositionOf(double eps, const MEDCouplingUMesh *mesh) const;
9545 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);
9546 const std::vector<int>& getConnOf(int pos) const { return get(pos)._edges; }
9547 const std::vector< MCAuto<INTERP_KERNEL::Edge> >& getEdgePtrOf(int pos) const { return get(pos)._edges_ptr; }
9548 MCAuto<MEDCouplingUMesh> getZeMesh() const { return _ze_mesh; }
9549 void feedEdgeInfoAt(double eps, int pos, int offset, int neighbors[2]) const;
9551 int getZePosOfEdgeGivenItsGlobalId(int pos) const;
9552 void updateEdgeInfo(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight);
9553 const CellInfo& get(int pos) const;
9554 CellInfo& get(int pos);
9556 std::vector<CellInfo> _pool;
9557 MCAuto<MEDCouplingUMesh> _ze_mesh;
9558 std::vector<EdgeInfo> _edge_info;
9561 VectorOfCellInfo::VectorOfCellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr):_pool(1)
9563 _pool[0]._edges=edges;
9564 _pool[0]._edges_ptr=edgesPtr;
9567 int VectorOfCellInfo::getPositionOf(double eps, const MEDCouplingUMesh *mesh) const
9570 throw INTERP_KERNEL::Exception("VectorOfCellSplitter::getPositionOf : empty !");
9573 const MEDCouplingUMesh *zeMesh(_ze_mesh);
9575 throw INTERP_KERNEL::Exception("VectorOfCellSplitter::getPositionOf : null aggregated mesh !");
9576 MCAuto<DataArrayDouble> barys(mesh->computeCellCenterOfMass());
9577 return zeMesh->getCellContainingPoint(barys->begin(),eps);
9580 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)
9582 get(pos);//to check pos
9583 bool isFast(pos==0 && _pool.size()==1);
9584 std::size_t sz(edges.size());
9585 // dealing with edges
9587 _edge_info.push_back(EdgeInfo(istart,iend,mesh1DInCase));
9589 _edge_info.push_back(EdgeInfo(istart,iend,pos,edgePtrs[0].back()));
9591 std::vector<CellInfo> pool(_pool.size()-1+sz);
9592 for(int i=0;i<pos;i++)
9594 for(std::size_t j=0;j<sz;j++)
9595 pool[pos+j]=CellInfo(edges[j],edgePtrs[j]);
9596 for(int i=pos+1;i<(int)_pool.size();i++)
9597 pool[i+sz-1]=_pool[i];
9601 updateEdgeInfo(pos,edgePtrs[0],edgePtrs[1]);
9609 std::vector< MCAuto<MEDCouplingUMesh> > ms;
9612 MCAuto<MEDCouplingUMesh> elt(static_cast<MEDCouplingUMesh *>(_ze_mesh->buildPartOfMySelfSlice(0,pos,true)));
9616 if(pos<_ze_mesh->getNumberOfCells()-1)
9618 MCAuto<MEDCouplingUMesh> elt(static_cast<MEDCouplingUMesh *>(_ze_mesh->buildPartOfMySelfSlice(pos+1,_ze_mesh->getNumberOfCells(),true)));
9621 std::vector< const MEDCouplingUMesh *> ms2(ms.size());
9622 for(std::size_t j=0;j<ms2.size();j++)
9624 _ze_mesh=MEDCouplingUMesh::MergeUMeshesOnSameCoords(ms2);
9627 void VectorOfCellInfo::feedEdgeInfoAt(double eps, int pos, int offset, int neighbors[2]) const
9629 _edge_info[getZePosOfEdgeGivenItsGlobalId(pos)].feedEdgeInfoAt(eps,_ze_mesh,offset,neighbors);
9632 int VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId(int pos) const
9635 throw INTERP_KERNEL::Exception("VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId : invalid id ! Must be >=0 !");
9637 for(std::vector<EdgeInfo>::const_iterator it=_edge_info.begin();it!=_edge_info.end();it++,ret++)
9639 if((*it).isInMyRange(pos))
9642 throw INTERP_KERNEL::Exception("VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId : invalid id !");
9645 void VectorOfCellInfo::updateEdgeInfo(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight)
9647 get(pos);//to check;
9648 if(_edge_info.empty())
9650 std::size_t sz(_edge_info.size()-1);
9651 for(std::size_t i=0;i<sz;i++)
9652 _edge_info[i].somethingHappendAt(pos,newLeft,newRight);
9655 const CellInfo& VectorOfCellInfo::get(int pos) const
9657 if(pos<0 || pos>=(int)_pool.size())
9658 throw INTERP_KERNEL::Exception("VectorOfCellSplitter::get const : invalid pos !");
9662 CellInfo& VectorOfCellInfo::get(int pos)
9664 if(pos<0 || pos>=(int)_pool.size())
9665 throw INTERP_KERNEL::Exception("VectorOfCellSplitter::get : invalid pos !");
9671 * - a \b closed set of edges ( \a allEdges and \a allEdgesPtr ) that defines the split descending 2D cell.
9672 * - \a splitMesh1D a split 2D curve mesh contained into 2D cell defined above.
9674 * This method returns the 2D mesh and feeds \a idsLeftRight using offset.
9676 * Algorithm : \a splitMesh1D is cut into contiguous parts. Each contiguous parts will build incrementally the output 2D cells.
9678 * \param [in] allEdges a list of pairs (beginNode, endNode). Linked with \a allEdgesPtr to get the equation of edge.
9680 MEDCouplingUMesh *BuildMesh2DCutInternal(double eps, const MEDCouplingUMesh *splitMesh1D, const std::vector<int>& allEdges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& allEdgesPtr, int offset,
9681 MCAuto<DataArrayInt>& idsLeftRight)
9683 int nbCellsInSplitMesh1D(splitMesh1D->getNumberOfCells());
9684 if(nbCellsInSplitMesh1D==0)
9685 throw INTERP_KERNEL::Exception("BuildMesh2DCutInternal : internal error ! input 1D mesh must have at least one cell !");
9686 const int *cSplitPtr(splitMesh1D->getNodalConnectivity()->begin()),*ciSplitPtr(splitMesh1D->getNodalConnectivityIndex()->begin());
9687 std::size_t nb(allEdges.size()),jj;
9689 throw INTERP_KERNEL::Exception("BuildMesh2DCutFrom : internal error 2 !");
9690 std::vector<int> edge1Bis(nb*2);
9691 std::vector< MCAuto<INTERP_KERNEL::Edge> > edge1BisPtr(nb*2);
9692 std::copy(allEdges.begin(),allEdges.end(),edge1Bis.begin());
9693 std::copy(allEdges.begin(),allEdges.end(),edge1Bis.begin()+nb);
9694 std::copy(allEdgesPtr.begin(),allEdgesPtr.end(),edge1BisPtr.begin());
9695 std::copy(allEdgesPtr.begin(),allEdgesPtr.end(),edge1BisPtr.begin()+nb);
9697 idsLeftRight=DataArrayInt::New(); idsLeftRight->alloc(nbCellsInSplitMesh1D*2); idsLeftRight->fillWithValue(-2); idsLeftRight->rearrange(2);
9698 int *idsLeftRightPtr(idsLeftRight->getPointer());
9699 VectorOfCellInfo pool(edge1Bis,edge1BisPtr);
9700 for(int iStart=0;iStart<nbCellsInSplitMesh1D;)
9701 {// split [0:nbCellsInSplitMesh1D) in contiguous parts [iStart:iEnd)
9703 for(;iEnd<nbCellsInSplitMesh1D;)
9705 for(jj=0;jj<nb && edge1Bis[2*jj+1]!=cSplitPtr[ciSplitPtr[iEnd]+2];jj++);
9711 if(iEnd<nbCellsInSplitMesh1D)
9714 MCAuto<MEDCouplingUMesh> partOfSplitMesh1D(static_cast<MEDCouplingUMesh *>(splitMesh1D->buildPartOfMySelfSlice(iStart,iEnd,1,true)));
9715 int pos(pool.getPositionOf(eps,partOfSplitMesh1D));
9717 MCAuto<MEDCouplingUMesh>retTmp(MEDCouplingUMesh::New("",2));
9718 retTmp->setCoords(splitMesh1D->getCoords());
9719 retTmp->allocateCells();
9721 std::vector< std::vector<int> > out0;
9722 std::vector< std::vector< MCAuto<INTERP_KERNEL::Edge> > > out1;
9724 BuildMesh2DCutInternal2(partOfSplitMesh1D,pool.getConnOf(pos),pool.getEdgePtrOf(pos),out0,out1);
9725 for(std::size_t cnt=0;cnt<out0.size();cnt++)
9726 AddCellInMesh2D(retTmp,out0[cnt],out1[cnt]);
9727 pool.setMeshAt(pos,retTmp,iStart,iEnd,partOfSplitMesh1D,out0,out1);
9731 for(int mm=0;mm<nbCellsInSplitMesh1D;mm++)
9732 pool.feedEdgeInfoAt(eps,mm,offset,idsLeftRightPtr+2*mm);
9733 return pool.getZeMesh().retn();
9736 MEDCouplingUMesh *BuildMesh2DCutFrom(double eps, int cellIdInMesh2D, const MEDCouplingUMesh *mesh2DDesc, const MEDCouplingUMesh *splitMesh1D,
9737 const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1, int offset,
9738 MCAuto<DataArrayInt>& idsLeftRight)
9740 const int *cdescPtr(mesh2DDesc->getNodalConnectivity()->begin()),*cidescPtr(mesh2DDesc->getNodalConnectivityIndex()->begin());
9742 std::vector<int> allEdges;
9743 std::vector< MCAuto<INTERP_KERNEL::Edge> > allEdgesPtr; // for each sub edge in splitMesh2D the uncut Edge object of the original mesh2D
9744 for(const int *it(descBg);it!=descEnd;it++) // for all edges in the descending connectivity of the 2D mesh in relative Fortran mode
9746 int edgeId(std::abs(*it)-1);
9747 std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9748 MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)cdescPtr[cidescPtr[edgeId]],cdescPtr+cidescPtr[edgeId]+1,mesh2DDesc->getCoords()->begin(),m));
9749 const std::vector<int>& edge1(intersectEdge1[edgeId]);
9751 allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9753 allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9754 std::size_t sz(edge1.size());
9755 for(std::size_t cnt=0;cnt<sz;cnt++)
9756 allEdgesPtr.push_back(ee);
9759 return BuildMesh2DCutInternal(eps,splitMesh1D,allEdges,allEdgesPtr,offset,idsLeftRight);
9762 bool AreEdgeEqual(const double *coo2D, const INTERP_KERNEL::CellModel& typ1, const int *conn1, const INTERP_KERNEL::CellModel& typ2, const int *conn2, double eps)
9764 if(!typ1.isQuadratic() && !typ2.isQuadratic())
9765 {//easy case comparison not
9766 return conn1[0]==conn2[0] && conn1[1]==conn2[1];
9768 else if(typ1.isQuadratic() && typ2.isQuadratic())
9770 bool status0(conn1[0]==conn2[0] && conn1[1]==conn2[1]);
9773 if(conn1[2]==conn2[2])
9775 const double *a(coo2D+2*conn1[2]),*b(coo2D+2*conn2[2]);
9776 double dist(sqrt((a[0]-b[0])*(a[0]-b[0])+(a[1]-b[1])*(a[1]-b[1])));
9780 {//only one is quadratic
9781 bool status0(conn1[0]==conn2[0] && conn1[1]==conn2[1]);
9784 const double *a(0),*bb(0),*be(0);
9785 if(typ1.isQuadratic())
9787 a=coo2D+2*conn1[2]; bb=coo2D+2*conn2[0]; be=coo2D+2*conn2[1];
9791 a=coo2D+2*conn2[2]; bb=coo2D+2*conn1[0]; be=coo2D+2*conn1[1];
9793 double b[2]; b[0]=(be[0]+bb[0])/2.; b[1]=(be[1]+bb[1])/2.;
9794 double dist(sqrt((a[0]-b[0])*(a[0]-b[0])+(a[1]-b[1])*(a[1]-b[1])));
9800 * This method returns among the cellIds [ \a candidatesIn2DBg , \a candidatesIn2DEnd ) in \a mesh2DSplit those exactly sharing \a cellIdInMesh1DSplitRelative in \a mesh1DSplit.
9801 * \a mesh2DSplit and \a mesh1DSplit are expected to share the coordinates array.
9803 * \param [in] cellIdInMesh1DSplitRelative is in Fortran mode using sign to specify direction.
9805 int FindRightCandidateAmong(const MEDCouplingUMesh *mesh2DSplit, const int *candidatesIn2DBg, const int *candidatesIn2DEnd, const MEDCouplingUMesh *mesh1DSplit, int cellIdInMesh1DSplitRelative, double eps)
9807 if(candidatesIn2DEnd==candidatesIn2DBg)
9808 throw INTERP_KERNEL::Exception("FindRightCandidateAmong : internal error 1 !");
9809 const double *coo(mesh2DSplit->getCoords()->begin());
9810 if(std::distance(candidatesIn2DBg,candidatesIn2DEnd)==1)
9811 return *candidatesIn2DBg;
9812 int edgeId(std::abs(cellIdInMesh1DSplitRelative)-1);
9813 MCAuto<MEDCouplingUMesh> cur1D(static_cast<MEDCouplingUMesh *>(mesh1DSplit->buildPartOfMySelf(&edgeId,&edgeId+1,true)));
9814 if(cellIdInMesh1DSplitRelative<0)
9815 cur1D->changeOrientationOfCells();
9816 const int *c1D(cur1D->getNodalConnectivity()->begin());
9817 const INTERP_KERNEL::CellModel& ref1DType(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c1D[0]));
9818 for(const int *it=candidatesIn2DBg;it!=candidatesIn2DEnd;it++)
9820 MCAuto<MEDCouplingUMesh> cur2D(static_cast<MEDCouplingUMesh *>(mesh2DSplit->buildPartOfMySelf(it,it+1,true)));
9821 const int *c(cur2D->getNodalConnectivity()->begin()),*ci(cur2D->getNodalConnectivityIndex()->begin());
9822 const INTERP_KERNEL::CellModel &cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[0]]));
9823 unsigned sz(cm.getNumberOfSons2(c+ci[0]+1,ci[1]-ci[0]-1));
9824 INTERP_KERNEL::AutoPtr<int> tmpPtr(new int[ci[1]-ci[0]]);
9825 for(unsigned it2=0;it2<sz;it2++)
9827 INTERP_KERNEL::NormalizedCellType typeOfSon;
9828 cm.fillSonCellNodalConnectivity2(it2,c+ci[0]+1,ci[1]-ci[0]-1,tmpPtr,typeOfSon);
9829 const INTERP_KERNEL::CellModel &curCM(INTERP_KERNEL::CellModel::GetCellModel(typeOfSon));
9830 if(AreEdgeEqual(coo,ref1DType,c1D+1,curCM,tmpPtr,eps))
9834 throw INTERP_KERNEL::Exception("FindRightCandidateAmong : internal error 2 ! Unable to find the edge among split cell !");
9840 * Partitions the first given 2D mesh using the second given 1D mesh as a tool.
9841 * 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
9842 * and finaly, in case of quadratic polygon the centers of edges new nodes.
9843 * The meshes should be in 2D space. In addition, returns two arrays mapping cells of the resulting mesh to cells of the input.
9845 * \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
9846 * 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)
9847 * \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
9848 * you can invoke orderConsecutiveCells1D on \a mesh1D.
9849 * \param [in] eps - precision used to perform intersections and localization operations.
9850 * \param [out] splitMesh2D - the result of the split of \a mesh2D mesh.
9851 * \param [out] splitMesh1D - the result of the split of \a mesh1D mesh.
9852 * \param [out] cellIdInMesh2D - the array that gives for each cell id \a i in \a splitMesh2D the id in \a mesh2D it comes from.
9853 * 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.
9854 * \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
9855 * and the cell in \a splitMesh2D on the right for the 2nt component. -1 means no cell.
9856 * 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.
9858 * \sa Intersect2DMeshes, orderConsecutiveCells1D, conformize2D, mergeNodes
9860 void MEDCouplingUMesh::Intersect2DMeshWith1DLine(const MEDCouplingUMesh *mesh2D, const MEDCouplingUMesh *mesh1D, double eps, MEDCouplingUMesh *&splitMesh2D, MEDCouplingUMesh *&splitMesh1D, DataArrayInt *&cellIdInMesh2D, DataArrayInt *&cellIdInMesh1D)
9862 if(!mesh2D || !mesh1D)
9863 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshWith1DLine : input meshes must be not NULL !");
9864 mesh2D->checkFullyDefined();
9865 mesh1D->checkFullyDefined();
9866 const std::vector<std::string>& compNames(mesh2D->getCoords()->getInfoOnComponents());
9867 if(mesh2D->getMeshDimension()!=2 || mesh2D->getSpaceDimension()!=2 || mesh1D->getMeshDimension()!=1 || mesh1D->getSpaceDimension()!=2)
9868 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshWith1DLine works with mesh2D with spacedim=meshdim=2 and mesh1D with meshdim=1 spaceDim=2 !");
9869 // Step 1: compute all edge intersections (new nodes)
9870 std::vector< std::vector<int> > intersectEdge1, colinear2, subDiv2;
9871 std::vector<double> addCoo,addCoordsQuadratic; // coordinates of newly created nodes
9872 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
9873 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
9875 // Build desc connectivity
9876 DataArrayInt *desc1(DataArrayInt::New()),*descIndx1(DataArrayInt::New()),*revDesc1(DataArrayInt::New()),*revDescIndx1(DataArrayInt::New());
9877 MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(revDesc1),dd4(revDescIndx1);
9878 MCAuto<MEDCouplingUMesh> m1Desc(mesh2D->buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1));
9879 std::map<int,int> mergedNodes;
9880 Intersect1DMeshes(m1Desc,mesh1D,eps,intersectEdge1,colinear2,subDiv2,addCoo,mergedNodes);
9881 // use mergeNodes to fix intersectEdge1
9882 for(std::vector< std::vector<int> >::iterator it0=intersectEdge1.begin();it0!=intersectEdge1.end();it0++)
9884 std::size_t n((*it0).size()/2);
9885 int eltStart((*it0)[0]),eltEnd((*it0)[2*n-1]);
9886 std::map<int,int>::const_iterator it1;
9887 it1=mergedNodes.find(eltStart);
9888 if(it1!=mergedNodes.end())
9889 (*it0)[0]=(*it1).second;
9890 it1=mergedNodes.find(eltEnd);
9891 if(it1!=mergedNodes.end())
9892 (*it0)[2*n-1]=(*it1).second;
9895 MCAuto<DataArrayDouble> addCooDa(DataArrayDouble::New());
9896 addCooDa->useArray(&addCoo[0],false,C_DEALLOC,(int)addCoo.size()/2,2);
9897 // Step 2: re-order newly created nodes according to the ordering found in m2
9898 std::vector< std::vector<int> > intersectEdge2;
9899 BuildIntersectEdges(m1Desc,mesh1D,addCoo,subDiv2,intersectEdge2);
9901 // Step 3: compute splitMesh1D
9902 MCAuto<DataArrayInt> idsInRet1Colinear,idsInDescMesh2DForIdsInRetColinear;
9903 MCAuto<DataArrayInt> ret2(DataArrayInt::New()); ret2->alloc(0,1);
9904 MCAuto<MEDCouplingUMesh> ret1(BuildMesh1DCutFrom(mesh1D,intersectEdge2,mesh2D->getCoords(),addCoo,mergedNodes,colinear2,intersectEdge1,
9905 idsInRet1Colinear,idsInDescMesh2DForIdsInRetColinear));
9906 MCAuto<DataArrayInt> ret3(DataArrayInt::New()); ret3->alloc(ret1->getNumberOfCells()*2,1); ret3->fillWithValue(std::numeric_limits<int>::max()); ret3->rearrange(2);
9907 MCAuto<DataArrayInt> idsInRet1NotColinear(idsInRet1Colinear->buildComplement(ret1->getNumberOfCells()));
9908 // deal with cells in mesh2D that are not cut but only some of their edges are
9909 MCAuto<DataArrayInt> idsInDesc2DToBeRefined(idsInDescMesh2DForIdsInRetColinear->deepCopy());
9910 idsInDesc2DToBeRefined->abs(); idsInDesc2DToBeRefined->applyLin(1,-1);
9911 idsInDesc2DToBeRefined=idsInDesc2DToBeRefined->buildUnique();
9912 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
9913 if(!idsInDesc2DToBeRefined->empty())
9915 DataArrayInt *out0(0),*outi0(0);
9916 MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
9917 MCAuto<DataArrayInt> outi0s(outi0);
9919 out0s=out0s->buildUnique();
9923 MCAuto<MEDCouplingUMesh> ret1NonCol(static_cast<MEDCouplingUMesh *>(ret1->buildPartOfMySelf(idsInRet1NotColinear->begin(),idsInRet1NotColinear->end())));
9924 MCAuto<DataArrayDouble> baryRet1(ret1NonCol->computeCellCenterOfMass());
9925 MCAuto<DataArrayInt> elts,eltsIndex;
9926 mesh2D->getCellsContainingPoints(baryRet1->begin(),baryRet1->getNumberOfTuples(),eps,elts,eltsIndex);
9927 MCAuto<DataArrayInt> eltsIndex2(eltsIndex->deltaShiftIndex());
9928 MCAuto<DataArrayInt> eltsIndex3(eltsIndex2->findIdsEqual(1));
9929 if(eltsIndex2->count(0)+eltsIndex3->getNumberOfTuples()!=ret1NonCol->getNumberOfCells())
9930 throw INTERP_KERNEL::Exception("Intersect2DMeshWith1DLine : internal error 1 !");
9931 MCAuto<DataArrayInt> cellsToBeModified(elts->buildUnique());
9932 MCAuto<DataArrayInt> untouchedCells(cellsToBeModified->buildComplement(mesh2D->getNumberOfCells()));
9933 if((DataArrayInt *)out0s)
9934 untouchedCells=untouchedCells->buildSubstraction(out0s);//if some edges in ret1 are colinear to descending mesh of mesh2D remove cells from untouched one
9935 std::vector< MCAuto<MEDCouplingUMesh> > outMesh2DSplit;
9936 // OK all is ready to insert in ret2 mesh
9937 if(!untouchedCells->empty())
9938 {// the most easy part, cells in mesh2D not impacted at all
9939 outMesh2DSplit.push_back(static_cast<MEDCouplingUMesh *>(mesh2D->buildPartOfMySelf(untouchedCells->begin(),untouchedCells->end())));
9940 outMesh2DSplit.back()->setCoords(ret1->getCoords());
9941 ret2->pushBackValsSilent(untouchedCells->begin(),untouchedCells->end());
9943 if((DataArrayInt *)out0s)
9944 {// here dealing with cells in out0s but not in cellsToBeModified
9945 MCAuto<DataArrayInt> fewModifiedCells(out0s->buildSubstraction(cellsToBeModified));
9946 const int *rdptr(dd3->begin()),*rdiptr(dd4->begin()),*dptr(dd1->begin()),*diptr(dd2->begin());
9947 for(const int *it=fewModifiedCells->begin();it!=fewModifiedCells->end();it++)
9949 outMesh2DSplit.push_back(BuildRefined2DCell(ret1->getCoords(),mesh2D,*it,dptr+diptr[*it],dptr+diptr[*it+1],intersectEdge1));
9950 ret1->setCoords(outMesh2DSplit.back()->getCoords());
9952 int offset(ret2->getNumberOfTuples());
9953 ret2->pushBackValsSilent(fewModifiedCells->begin(),fewModifiedCells->end());
9954 MCAuto<DataArrayInt> partOfRet3(DataArrayInt::New()); partOfRet3->alloc(2*idsInRet1Colinear->getNumberOfTuples(),1);
9955 partOfRet3->fillWithValue(std::numeric_limits<int>::max()); partOfRet3->rearrange(2);
9956 int kk(0),*ret3ptr(partOfRet3->getPointer());
9957 for(const int *it=idsInDescMesh2DForIdsInRetColinear->begin();it!=idsInDescMesh2DForIdsInRetColinear->end();it++,kk++)
9959 int faceId(std::abs(*it)-1);
9960 for(const int *it2=rdptr+rdiptr[faceId];it2!=rdptr+rdiptr[faceId+1];it2++)
9962 int tmp(fewModifiedCells->findIdFirstEqual(*it2));
9965 if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],-(*it))!=dptr+diptr[*it2+1])
9966 ret3ptr[2*kk]=tmp+offset;
9967 if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],(*it))!=dptr+diptr[*it2+1])
9968 ret3ptr[2*kk+1]=tmp+offset;
9971 {//the current edge is shared by a 2D cell that will be split just after
9972 if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],-(*it))!=dptr+diptr[*it2+1])
9973 ret3ptr[2*kk]=-(*it2+1);
9974 if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],(*it))!=dptr+diptr[*it2+1])
9975 ret3ptr[2*kk+1]=-(*it2+1);
9979 m1Desc->setCoords(ret1->getCoords());
9980 ret1NonCol->setCoords(ret1->getCoords());
9981 ret3->setPartOfValues3(partOfRet3,idsInRet1Colinear->begin(),idsInRet1Colinear->end(),0,2,1,true);
9982 if(!outMesh2DSplit.empty())
9984 DataArrayDouble *da(outMesh2DSplit.back()->getCoords());
9985 for(std::vector< MCAuto<MEDCouplingUMesh> >::iterator itt=outMesh2DSplit.begin();itt!=outMesh2DSplit.end();itt++)
9986 (*itt)->setCoords(da);
9989 cellsToBeModified=cellsToBeModified->buildUniqueNotSorted();
9990 for(const int *it=cellsToBeModified->begin();it!=cellsToBeModified->end();it++)
9992 MCAuto<DataArrayInt> idsNonColPerCell(elts->findIdsEqual(*it));
9993 idsNonColPerCell->transformWithIndArr(eltsIndex3->begin(),eltsIndex3->end());
9994 MCAuto<DataArrayInt> idsNonColPerCell2(idsInRet1NotColinear->selectByTupleId(idsNonColPerCell->begin(),idsNonColPerCell->end()));
9995 MCAuto<MEDCouplingUMesh> partOfMesh1CuttingCur2DCell(static_cast<MEDCouplingUMesh *>(ret1NonCol->buildPartOfMySelf(idsNonColPerCell->begin(),idsNonColPerCell->end())));
9996 MCAuto<DataArrayInt> partOfRet3;
9997 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));
9998 ret3->setPartOfValues3(partOfRet3,idsNonColPerCell2->begin(),idsNonColPerCell2->end(),0,2,1,true);
9999 outMesh2DSplit.push_back(splitOfOneCell);
10000 for(int i=0;i<splitOfOneCell->getNumberOfCells();i++)
10001 ret2->pushBackSilent(*it);
10004 std::size_t nbOfMeshes(outMesh2DSplit.size());
10005 std::vector<const MEDCouplingUMesh *> tmp(nbOfMeshes);
10006 for(std::size_t i=0;i<nbOfMeshes;i++)
10007 tmp[i]=outMesh2DSplit[i];
10009 ret1->getCoords()->setInfoOnComponents(compNames);
10010 MCAuto<MEDCouplingUMesh> ret2D(MEDCouplingUMesh::MergeUMeshesOnSameCoords(tmp));
10011 // To finish - filter ret3 - std::numeric_limits<int>::max() -> -1 - negate values must be resolved.
10012 ret3->rearrange(1);
10013 MCAuto<DataArrayInt> edgesToDealWith(ret3->findIdsStricltyNegative());
10014 for(const int *it=edgesToDealWith->begin();it!=edgesToDealWith->end();it++)
10016 int old2DCellId(-ret3->getIJ(*it,0)-1);
10017 MCAuto<DataArrayInt> candidates(ret2->findIdsEqual(old2DCellId));
10018 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
10020 ret3->changeValue(std::numeric_limits<int>::max(),-1);
10021 ret3->rearrange(2);
10023 splitMesh1D=ret1.retn();
10024 splitMesh2D=ret2D.retn();
10025 cellIdInMesh2D=ret2.retn();
10026 cellIdInMesh1D=ret3.retn();
10030 * Private. Third step of the partitioning algorithm (Intersect2DMeshes): reconstruct full 2D cells from the
10031 * (newly created) nodes corresponding to the edge intersections.
10033 * @param[out] cr, crI connectivity of the resulting mesh
10034 * @param[out] cNb1, cNb2 correspondance arrays giving for the merged mesh the initial cells IDs in m1 / m2
10035 * TODO: describe input parameters
10037 void MEDCouplingUMesh::BuildIntersecting2DCellsFromEdges(double eps, const MEDCouplingUMesh *m1, const int *desc1, const int *descIndx1,
10038 const std::vector<std::vector<int> >& intesctEdges1, const std::vector< std::vector<int> >& colinear2,
10039 const MEDCouplingUMesh *m2, const int *desc2, const int *descIndx2, const std::vector<std::vector<int> >& intesctEdges2,
10040 const std::vector<double>& addCoords,
10041 std::vector<double>& addCoordsQuadratic, std::vector<int>& cr, std::vector<int>& crI, std::vector<int>& cNb1, std::vector<int>& cNb2)
10043 static const int SPACEDIM=2;
10044 const double *coo1(m1->getCoords()->getConstPointer());
10045 const int *conn1(m1->getNodalConnectivity()->getConstPointer()),*connI1(m1->getNodalConnectivityIndex()->getConstPointer());
10046 int offset1(m1->getNumberOfNodes());
10047 const double *coo2(m2->getCoords()->getConstPointer());
10048 const int *conn2(m2->getNodalConnectivity()->getConstPointer()),*connI2(m2->getNodalConnectivityIndex()->getConstPointer());
10049 int offset2(offset1+m2->getNumberOfNodes());
10050 int offset3(offset2+((int)addCoords.size())/2);
10051 MCAuto<DataArrayDouble> bbox1Arr(m1->getBoundingBoxForBBTree()),bbox2Arr(m2->getBoundingBoxForBBTree());
10052 const double *bbox1(bbox1Arr->begin()),*bbox2(bbox2Arr->begin());
10053 // Here a BBTree on 2D-cells, not on segments:
10054 BBTree<SPACEDIM,int> myTree(bbox2,0,0,m2->getNumberOfCells(),eps);
10055 int ncell1(m1->getNumberOfCells());
10057 for(int i=0;i<ncell1;i++)
10059 std::vector<int> candidates2;
10060 myTree.getIntersectingElems(bbox1+i*2*SPACEDIM,candidates2);
10061 std::map<INTERP_KERNEL::Node *,int> mapp;
10062 std::map<int,INTERP_KERNEL::Node *> mappRev;
10063 INTERP_KERNEL::QuadraticPolygon pol1;
10064 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn1[connI1[i]];
10065 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
10066 // Populate mapp and mappRev with nodes from the current cell (i) from mesh1 - this also builds the Node* objects:
10067 MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,/* output */mapp,mappRev);
10068 // pol1 is the full cell from mesh2, in QP format, with all the additional intersecting nodes.
10069 pol1.buildFromCrudeDataArray(mappRev,cm.isQuadratic(),conn1+connI1[i]+1,coo1,
10070 desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1);
10072 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
10073 std::set<INTERP_KERNEL::Edge *> edgesBoundary2;// store all edges that are on boundary of (pol2 intersect pol1) minus edges on pol1.
10074 INTERP_KERNEL::IteratorOnComposedEdge it1(&pol1);
10075 for(it1.first();!it1.finished();it1.next())
10076 edges1.insert(it1.current()->getPtr());
10078 std::map<int,std::vector<INTERP_KERNEL::ElementaryEdge *> > edgesIn2ForShare; // common edges
10079 std::vector<INTERP_KERNEL::QuadraticPolygon> pol2s(candidates2.size());
10081 for(std::vector<int>::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++,ii++)
10083 INTERP_KERNEL::NormalizedCellType typ2=(INTERP_KERNEL::NormalizedCellType)conn2[connI2[*it2]];
10084 const INTERP_KERNEL::CellModel& cm2=INTERP_KERNEL::CellModel::GetCellModel(typ2);
10085 // Complete mapping with elements coming from the current cell it2 in mesh2:
10086 MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,/* output */mapp,mappRev);
10087 // pol2 is the new QP in the final merged result.
10088 pol2s[ii].buildFromCrudeDataArray2(mappRev,cm2.isQuadratic(),conn2+connI2[*it2]+1,coo2,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,
10089 pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2, /* output */ edgesIn2ForShare);
10092 for(std::vector<int>::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++,ii++)
10094 INTERP_KERNEL::ComposedEdge::InitLocationsWithOther(pol1,pol2s[ii]);
10095 pol2s[ii].updateLocOfEdgeFromCrudeDataArray2(desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2);
10096 //MEDCouplingUMeshAssignOnLoc(pol1,pol2,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,colinear2);
10097 pol1.buildPartitionsAbs(pol2s[ii],edges1,edgesBoundary2,mapp,i,*it2,offset3,addCoordsQuadratic,cr,crI,cNb1,cNb2);
10099 // Deals with remaining (non-consumed) edges from m1: these are the edges that were never touched
10100 // by m2 but that we still want to keep in the final result.
10101 if(!edges1.empty())
10105 INTERP_KERNEL::QuadraticPolygon::ComputeResidual(pol1,edges1,edgesBoundary2,mapp,offset3,i,addCoordsQuadratic,cr,crI,cNb1,cNb2);
10107 catch(INTERP_KERNEL::Exception& e)
10109 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();
10110 throw INTERP_KERNEL::Exception(oss.str().c_str());
10113 for(std::map<int,INTERP_KERNEL::Node *>::const_iterator it=mappRev.begin();it!=mappRev.end();it++)
10114 (*it).second->decrRef();
10119 * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
10120 * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
10121 * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
10122 * The caller is to deal with the resulting DataArrayInt.
10123 * \throw If the coordinate array is not set.
10124 * \throw If the nodal connectivity of the cells is not defined.
10125 * \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
10126 * \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
10128 * \sa DataArrayInt::sortEachPairToMakeALinkedList
10130 DataArrayInt *MEDCouplingUMesh::orderConsecutiveCells1D() const
10132 checkFullyDefined();
10133 if(getMeshDimension()!=1)
10134 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
10136 // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
10137 MCAuto<DataArrayInt> _d(DataArrayInt::New()),_dI(DataArrayInt::New());
10138 MCAuto<DataArrayInt> _rD(DataArrayInt::New()),_rDI(DataArrayInt::New());
10139 MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
10140 const int *d(_d->getConstPointer()), *dI(_dI->getConstPointer());
10141 const int *rD(_rD->getConstPointer()), *rDI(_rDI->getConstPointer());
10142 MCAuto<DataArrayInt> _dsi(_rDI->deltaShiftIndex());
10143 const int * dsi(_dsi->getConstPointer());
10144 MCAuto<DataArrayInt> dsii = _dsi->findIdsNotInRange(0,3);
10146 if (dsii->getNumberOfTuples())
10147 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
10149 int nc(getNumberOfCells());
10150 MCAuto<DataArrayInt> result(DataArrayInt::New());
10151 result->alloc(nc,1);
10153 // set of edges not used so far
10154 std::set<int> edgeSet;
10155 for (int i=0; i<nc; edgeSet.insert(i), i++);
10159 // while we have points with only one neighbor segments
10162 std::list<int> linePiece;
10163 // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
10164 for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
10166 // Fill the list forward (resp. backward) from the start segment:
10167 int activeSeg = startSeg;
10168 int prevPointId = -20;
10170 while (!edgeSet.empty())
10172 if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
10175 linePiece.push_back(activeSeg);
10177 linePiece.push_front(activeSeg);
10178 edgeSet.erase(activeSeg);
10181 int ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
10182 ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
10183 if (dsi[ptId] == 1) // hitting the end of the line
10185 prevPointId = ptId;
10186 int seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
10187 activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
10190 // Done, save final piece into DA:
10191 std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
10192 newIdx += linePiece.size();
10194 // identify next valid start segment (one which is not consumed)
10195 if(!edgeSet.empty())
10196 startSeg = *(edgeSet.begin());
10198 while (!edgeSet.empty());
10199 return result.retn();
10204 void IKGeo2DInternalMapper2(INTERP_KERNEL::Node *n, const std::map<MCAuto<INTERP_KERNEL::Node>,int>& m, int forbVal0, int forbVal1, std::vector<int>& isect)
10206 MCAuto<INTERP_KERNEL::Node> nTmp(n); nTmp->incrRef();
10207 std::map<MCAuto<INTERP_KERNEL::Node>,int>::const_iterator it(m.find(nTmp));
10209 throw INTERP_KERNEL::Exception("Internal error in remapping !");
10210 int v((*it).second);
10211 if(v==forbVal0 || v==forbVal1)
10213 if(std::find(isect.begin(),isect.end(),v)==isect.end())
10214 isect.push_back(v);
10217 bool IKGeo2DInternalMapper(const INTERP_KERNEL::ComposedEdge& c, const std::map<MCAuto<INTERP_KERNEL::Node>,int>& m, int forbVal0, int forbVal1, std::vector<int>& isect)
10222 bool presenceOfOn(false);
10223 for(int i=0;i<sz;i++)
10225 INTERP_KERNEL::ElementaryEdge *e(c[i]);
10226 if(e->getLoc()!=INTERP_KERNEL::FULL_ON_1)
10228 IKGeo2DInternalMapper2(e->getStartNode(),m,forbVal0,forbVal1,isect);
10229 IKGeo2DInternalMapper2(e->getEndNode(),m,forbVal0,forbVal1,isect);
10231 return presenceOfOn;
10237 * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
10238 * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
10239 * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
10240 * a minimal creation of new nodes is wanted.
10241 * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
10242 * nodes if a SEG3 is split without information of middle.
10243 * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
10244 * avoid to have a non conform mesh.
10246 * \return int - the number of new nodes created (in most of cases 0).
10248 * \throw If \a this is not coherent.
10249 * \throw If \a this has not spaceDim equal to 2.
10250 * \throw If \a this has not meshDim equal to 2.
10251 * \throw If some subcells needed to be split are orphan.
10252 * \sa MEDCouplingUMesh::conformize2D
10254 int MEDCouplingUMesh::split2DCells(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *midOpt, const DataArrayInt *midOptI)
10256 if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
10257 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
10258 desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
10259 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10260 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10261 if(midOpt==0 && midOptI==0)
10263 split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
10266 else if(midOpt!=0 && midOptI!=0)
10267 return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
10269 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
10273 * \b WARNING this method is \b potentially \b non \b const (if returned array is empty).
10274 * \b WARNING this method lead to have a non geometric type sorted mesh (for MED file users) !
10275 * 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
10276 * 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).
10277 * 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.
10279 * Whatever the returned value, this method does not alter the order of cells in \a this neither the orientation of cells.
10280 * The modified cells, if any, are systematically declared as NORM_POLYGON or NORM_QPOLYG depending on the initial quadraticness of geometric type.
10282 * This method expects that \b this has a meshDim equal 2 and spaceDim equal to 2 too.
10283 * This method expects that all nodes in \a this are not closer than \a eps.
10284 * If it is not the case you can invoke MEDCouplingUMesh::mergeNodes before calling this method.
10286 * \param [in] eps the relative error to detect merged edges.
10287 * \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
10288 * that the user is expected to deal with.
10290 * \throw If \a this is not coherent.
10291 * \throw If \a this has not spaceDim equal to 2.
10292 * \throw If \a this has not meshDim equal to 2.
10293 * \sa MEDCouplingUMesh::mergeNodes, MEDCouplingUMesh::split2DCells
10295 DataArrayInt *MEDCouplingUMesh::conformize2D(double eps)
10297 static const int SPACEDIM=2;
10298 checkConsistencyLight();
10299 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10300 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::conformize2D : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10301 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
10302 MCAuto<MEDCouplingUMesh> mDesc(buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));
10303 const int *c(mDesc->getNodalConnectivity()->getConstPointer()),*ci(mDesc->getNodalConnectivityIndex()->getConstPointer()),*rd(revDesc1->getConstPointer()),*rdi(revDescIndx1->getConstPointer());
10304 MCAuto<DataArrayDouble> bboxArr(mDesc->getBoundingBoxForBBTree());
10305 const double *bbox(bboxArr->begin()),*coords(getCoords()->begin());
10306 int nCell(getNumberOfCells()),nDescCell(mDesc->getNumberOfCells());
10307 std::vector< std::vector<int> > intersectEdge(nDescCell),overlapEdge(nDescCell);
10308 std::vector<double> addCoo;
10309 BBTree<SPACEDIM,int> myTree(bbox,0,0,nDescCell,-eps);
10310 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10311 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10312 for(int i=0;i<nDescCell;i++)
10314 std::vector<int> candidates;
10315 myTree.getIntersectingElems(bbox+i*2*SPACEDIM,candidates);
10316 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
10319 std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
10320 INTERP_KERNEL::Edge *e1(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coords,m)),
10321 *e2(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[*it]],c+ci[*it]+1,coords,m));
10322 INTERP_KERNEL::MergePoints merge;
10323 INTERP_KERNEL::QuadraticPolygon c1,c2;
10324 e1->intersectWith(e2,merge,c1,c2);
10325 e1->decrRef(); e2->decrRef();
10326 if(IKGeo2DInternalMapper(c1,m,c[ci[i]+1],c[ci[i]+2],intersectEdge[i]))
10327 overlapEdge[i].push_back(*it);
10328 if(IKGeo2DInternalMapper(c2,m,c[ci[*it]+1],c[ci[*it]+2],intersectEdge[*it]))
10329 overlapEdge[*it].push_back(i);
10332 // splitting done. sort intersect point in intersectEdge.
10333 std::vector< std::vector<int> > middle(nDescCell);
10334 int nbOf2DCellsToBeSplit(0);
10335 bool middleNeedsToBeUsed(false);
10336 std::vector<bool> cells2DToTreat(nDescCell,false);
10337 for(int i=0;i<nDescCell;i++)
10339 std::vector<int>& isect(intersectEdge[i]);
10340 int sz((int)isect.size());
10343 std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
10344 INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coords,m));
10345 e->sortSubNodesAbs(coords,isect);
10350 int idx0(rdi[i]),idx1(rdi[i+1]);
10352 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::conformize2D : internal error #0 !");
10353 if(!cells2DToTreat[rd[idx0]])
10355 cells2DToTreat[rd[idx0]]=true;
10356 nbOf2DCellsToBeSplit++;
10358 // try to reuse at most eventual 'middle' of SEG3
10359 std::vector<int>& mid(middle[i]);
10360 mid.resize(sz+1,-1);
10361 if((INTERP_KERNEL::NormalizedCellType)c[ci[i]]==INTERP_KERNEL::NORM_SEG3)
10363 middleNeedsToBeUsed=true;
10364 const std::vector<int>& candidates(overlapEdge[i]);
10365 std::vector<int> trueCandidates;
10366 for(std::vector<int>::const_iterator itc=candidates.begin();itc!=candidates.end();itc++)
10367 if((INTERP_KERNEL::NormalizedCellType)c[ci[*itc]]==INTERP_KERNEL::NORM_SEG3)
10368 trueCandidates.push_back(*itc);
10369 int stNode(c[ci[i]+1]),endNode(isect[0]);
10370 for(int j=0;j<sz+1;j++)
10372 for(std::vector<int>::const_iterator itc=trueCandidates.begin();itc!=trueCandidates.end();itc++)
10374 int tmpSt(c[ci[*itc]+1]),tmpEnd(c[ci[*itc]+2]);
10375 if((tmpSt==stNode && tmpEnd==endNode) || (tmpSt==endNode && tmpEnd==stNode))
10376 { mid[j]=*itc; break; }
10379 endNode=j<sz-1?isect[j+1]:c[ci[i]+2];
10384 MCAuto<DataArrayInt> ret(DataArrayInt::New()),notRet(DataArrayInt::New()); ret->alloc(nbOf2DCellsToBeSplit,1);
10385 if(nbOf2DCellsToBeSplit==0)
10388 int *retPtr(ret->getPointer());
10389 for(int i=0;i<nCell;i++)
10390 if(cells2DToTreat[i])
10393 MCAuto<DataArrayInt> mSafe,nSafe,oSafe,pSafe,qSafe,rSafe;
10394 DataArrayInt *m(0),*n(0),*o(0),*p(0),*q(0),*r(0);
10395 MEDCouplingUMesh::ExtractFromIndexedArrays(ret->begin(),ret->end(),desc1,descIndx1,m,n); mSafe=m; nSafe=n;
10396 DataArrayInt::PutIntoToSkylineFrmt(intersectEdge,o,p); oSafe=o; pSafe=p;
10397 if(middleNeedsToBeUsed)
10398 { DataArrayInt::PutIntoToSkylineFrmt(middle,q,r); qSafe=q; rSafe=r; }
10399 MCAuto<MEDCouplingUMesh> modif(static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(ret->begin(),ret->end(),true)));
10400 int nbOfNodesCreated(modif->split2DCells(mSafe,nSafe,oSafe,pSafe,qSafe,rSafe));
10401 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.
10402 setPartOfMySelf(ret->begin(),ret->end(),*modif);
10404 bool areNodesMerged; int newNbOfNodes;
10405 if(nbOfNodesCreated!=0)
10406 MCAuto<DataArrayInt> tmp(mergeNodes(eps,areNodesMerged,newNbOfNodes));
10412 * 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.
10413 * 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).
10414 * 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
10415 * to invoke MEDCouplingUMesh::mergeNodes and MEDCouplingUMesh::conformize2D right after this call.
10416 * 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
10417 * new nodes for center of merged edges is are systematically created and appended at the end of the previously existing nodes.
10419 * 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
10420 * using new instance, idem for coordinates.
10422 * 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.
10424 * \return DataArrayInt * - The list of cellIds in \a this that have at least one edge colinearized.
10426 * \throw If \a this is not coherent.
10427 * \throw If \a this has not spaceDim equal to 2.
10428 * \throw If \a this has not meshDim equal to 2.
10430 * \sa MEDCouplingUMesh::conformize2D, MEDCouplingUMesh::mergeNodes, MEDCouplingUMesh::convexEnvelop2D.
10432 DataArrayInt *MEDCouplingUMesh::colinearize2D(double eps)
10434 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
10435 checkConsistencyLight();
10436 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10437 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::colinearize2D : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10438 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10439 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10440 int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
10441 const int *cptr(_nodal_connec->begin()),*ciptr(_nodal_connec_index->begin());
10442 MCAuto<DataArrayInt> newc(DataArrayInt::New()),newci(DataArrayInt::New()); newci->alloc(nbOfCells+1,1); newc->alloc(0,1); newci->setIJ(0,0,0);
10443 MCAuto<DataArrayDouble> appendedCoords(DataArrayDouble::New()); appendedCoords->alloc(0,1);//1 not 2 it is not a bug.
10444 const double *coords(_coords->begin());
10445 int *newciptr(newci->getPointer());
10446 for(int i=0;i<nbOfCells;i++,newciptr++,ciptr++)
10448 if(Colinearize2DCell(coords,cptr+ciptr[0],cptr+ciptr[1],nbOfNodes,newc,appendedCoords))
10449 ret->pushBackSilent(i);
10450 newciptr[1]=newc->getNumberOfTuples();
10455 if(!appendedCoords->empty())
10457 appendedCoords->rearrange(2);
10458 MCAuto<DataArrayDouble> newCoords(DataArrayDouble::Aggregate(getCoords(),appendedCoords));//treat info on components
10460 setCoords(newCoords);
10463 setConnectivity(newc,newci,true);
10468 * \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.
10469 * 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.
10470 * And for each j in [1,n) intersect[i][2*(j-1)+1]==intersect[i][2*j].
10471 * \param [out] subDiv2 - for each cell in \a m2Desc returns nodes that split it using convention \a m1Desc first, then \a m2Desc, then addCoo
10472 * \param [out] colinear2 - for each cell in \a m2Desc returns the edges in \a m1Desc that are colinear to it.
10473 * \param [out] addCoo - nodes to be append at the end
10474 * \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.
10476 void MEDCouplingUMesh::Intersect1DMeshes(const MEDCouplingUMesh *m1Desc, const MEDCouplingUMesh *m2Desc, double eps,
10477 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)
10479 static const int SPACEDIM=2;
10480 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10481 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10482 const int *c1(m1Desc->getNodalConnectivity()->getConstPointer()),*ci1(m1Desc->getNodalConnectivityIndex()->getConstPointer());
10483 // Build BB tree of all edges in the tool mesh (second mesh)
10484 MCAuto<DataArrayDouble> bbox1Arr(m1Desc->getBoundingBoxForBBTree()),bbox2Arr(m2Desc->getBoundingBoxForBBTree());
10485 const double *bbox1(bbox1Arr->begin()),*bbox2(bbox2Arr->begin());
10486 int nDescCell1(m1Desc->getNumberOfCells()),nDescCell2(m2Desc->getNumberOfCells());
10487 intersectEdge1.resize(nDescCell1);
10488 colinear2.resize(nDescCell2);
10489 subDiv2.resize(nDescCell2);
10490 BBTree<SPACEDIM,int> myTree(bbox2,0,0,m2Desc->getNumberOfCells(),-eps);
10492 std::vector<int> candidates1(1);
10493 int offset1(m1Desc->getNumberOfNodes());
10494 int offset2(offset1+m2Desc->getNumberOfNodes());
10495 for(int i=0;i<nDescCell1;i++) // for all edges in the first mesh
10497 std::vector<int> candidates2; // edges of mesh2 candidate for intersection
10498 myTree.getIntersectingElems(bbox1+i*2*SPACEDIM,candidates2);
10499 if(!candidates2.empty()) // candidates2 holds edges from the second mesh potentially intersecting current edge i in mesh1
10501 std::map<INTERP_KERNEL::Node *,int> map1,map2;
10502 // pol2 is not necessarily a closed polygon: just a set of (quadratic) edges (same as candidates2) in the Geometric DS format
10503 INTERP_KERNEL::QuadraticPolygon *pol2=MEDCouplingUMeshBuildQPFromMesh(m2Desc,candidates2,map2);
10505 INTERP_KERNEL::QuadraticPolygon *pol1=MEDCouplingUMeshBuildQPFromMesh(m1Desc,candidates1,map1);
10506 // 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
10507 // This trick guarantees that Node * are discriminant (i.e. form a unique identifier)
10508 std::set<INTERP_KERNEL::Node *> nodes;
10509 pol1->getAllNodes(nodes); pol2->getAllNodes(nodes);
10510 std::size_t szz(nodes.size());
10511 std::vector< MCAuto<INTERP_KERNEL::Node> > nodesSafe(szz);
10512 std::set<INTERP_KERNEL::Node *>::const_iterator itt(nodes.begin());
10513 for(std::size_t iii=0;iii<szz;iii++,itt++)
10514 { (*itt)->incrRef(); nodesSafe[iii]=*itt; }
10515 // end of protection
10516 // Performs egde cutting:
10517 pol1->splitAbs(*pol2,map1,map2,offset1,offset2,candidates2,intersectEdge1[i],i,colinear2,subDiv2,addCoo,mergedNodes);
10522 // Copy the edge (take only the two first points, ie discard quadratic point at this stage)
10523 intersectEdge1[i].insert(intersectEdge1[i].end(),c1+ci1[i]+1,c1+ci1[i]+3);
10528 * This method is private and is the first step of Partition of 2D mesh (spaceDim==2 and meshDim==2).
10529 * It builds the descending connectivity of the two meshes, and then using a binary tree
10530 * it computes the edge intersections. This results in new points being created : they're stored in addCoo.
10531 * Documentation about parameters colinear2 and subDiv2 can be found in method QuadraticPolygon::splitAbs().
10533 void MEDCouplingUMesh::IntersectDescending2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2, double eps,
10534 std::vector< std::vector<int> >& intersectEdge1, std::vector< std::vector<int> >& colinear2, std::vector< std::vector<int> >& subDiv2,
10535 MEDCouplingUMesh *& m1Desc, DataArrayInt *&desc1, DataArrayInt *&descIndx1, DataArrayInt *&revDesc1, DataArrayInt *&revDescIndx1,
10536 std::vector<double>& addCoo,
10537 MEDCouplingUMesh *& m2Desc, DataArrayInt *&desc2, DataArrayInt *&descIndx2, DataArrayInt *&revDesc2, DataArrayInt *&revDescIndx2)
10539 // Build desc connectivity
10540 desc1=DataArrayInt::New(); descIndx1=DataArrayInt::New(); revDesc1=DataArrayInt::New(); revDescIndx1=DataArrayInt::New();
10541 desc2=DataArrayInt::New();
10542 descIndx2=DataArrayInt::New();
10543 revDesc2=DataArrayInt::New();
10544 revDescIndx2=DataArrayInt::New();
10545 MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(revDesc1),dd4(revDescIndx1);
10546 MCAuto<DataArrayInt> dd5(desc2),dd6(descIndx2),dd7(revDesc2),dd8(revDescIndx2);
10547 m1Desc=m1->buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1);
10548 m2Desc=m2->buildDescendingConnectivity2(desc2,descIndx2,revDesc2,revDescIndx2);
10549 MCAuto<MEDCouplingUMesh> dd9(m1Desc),dd10(m2Desc);
10550 std::map<int,int> notUsedMap;
10551 Intersect1DMeshes(m1Desc,m2Desc,eps,intersectEdge1,colinear2,subDiv2,addCoo,notUsedMap);
10552 m1Desc->incrRef(); desc1->incrRef(); descIndx1->incrRef(); revDesc1->incrRef(); revDescIndx1->incrRef();
10553 m2Desc->incrRef(); desc2->incrRef(); descIndx2->incrRef(); revDesc2->incrRef(); revDescIndx2->incrRef();
10557 * This method performs the 2nd step of Partition of 2D mesh.
10558 * This method has 4 inputs :
10559 * - a mesh 'm1' with meshDim==1 and a SpaceDim==2
10560 * - a mesh 'm2' with meshDim==1 and a SpaceDim==2
10561 * - subDiv of size 'm2->getNumberOfCells()' that lists for each seg cell in 'm' the splitting node ids randomly sorted.
10562 * 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'
10563 * Nodes end up lying consecutively on a cutted edge.
10564 * \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.
10565 * (Only present for its coords in case of 'subDiv' shares some nodes of 'm1')
10566 * \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.
10567 * \param addCoo input parameter with additional nodes linked to intersection of the 2 meshes.
10568 * \param[out] intersectEdge the same content as subDiv, but correclty oriented.
10570 void MEDCouplingUMesh::BuildIntersectEdges(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2,
10571 const std::vector<double>& addCoo,
10572 const std::vector< std::vector<int> >& subDiv, std::vector< std::vector<int> >& intersectEdge)
10574 int offset1=m1->getNumberOfNodes();
10575 int ncell=m2->getNumberOfCells();
10576 const int *c=m2->getNodalConnectivity()->getConstPointer();
10577 const int *cI=m2->getNodalConnectivityIndex()->getConstPointer();
10578 const double *coo=m2->getCoords()->getConstPointer();
10579 const double *cooBis=m1->getCoords()->getConstPointer();
10580 int offset2=offset1+m2->getNumberOfNodes();
10581 intersectEdge.resize(ncell);
10582 for(int i=0;i<ncell;i++,cI++)
10584 const std::vector<int>& divs=subDiv[i];
10585 int nnode=cI[1]-cI[0]-1;
10586 std::map<int, std::pair<INTERP_KERNEL::Node *,bool> > mapp2;
10587 std::map<INTERP_KERNEL::Node *, int> mapp22;
10588 for(int j=0;j<nnode;j++)
10590 INTERP_KERNEL::Node *nn=new INTERP_KERNEL::Node(coo[2*c[(*cI)+j+1]],coo[2*c[(*cI)+j+1]+1]);
10591 int nnid=c[(*cI)+j+1];
10592 mapp2[nnid]=std::pair<INTERP_KERNEL::Node *,bool>(nn,true);
10593 mapp22[nn]=nnid+offset1;
10595 INTERP_KERNEL::Edge *e=MEDCouplingUMeshBuildQPFromEdge((INTERP_KERNEL::NormalizedCellType)c[*cI],mapp2,c+(*cI)+1);
10596 for(std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >::const_iterator it=mapp2.begin();it!=mapp2.end();it++)
10597 ((*it).second.first)->decrRef();
10598 std::vector<INTERP_KERNEL::Node *> addNodes(divs.size());
10599 std::map<INTERP_KERNEL::Node *,int> mapp3;
10600 for(std::size_t j=0;j<divs.size();j++)
10603 INTERP_KERNEL::Node *tmp=0;
10605 tmp=new INTERP_KERNEL::Node(cooBis[2*id],cooBis[2*id+1]);
10606 else if(id<offset2)
10607 tmp=new INTERP_KERNEL::Node(coo[2*(id-offset1)],coo[2*(id-offset1)+1]);//if it happens, bad news mesh 'm2' is non conform.
10609 tmp=new INTERP_KERNEL::Node(addCoo[2*(id-offset2)],addCoo[2*(id-offset2)+1]);
10613 e->sortIdsAbs(addNodes,mapp22,mapp3,intersectEdge[i]);
10614 for(std::vector<INTERP_KERNEL::Node *>::const_iterator it=addNodes.begin();it!=addNodes.end();it++)
10621 * 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).
10622 * 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
10623 * with a plane. The result will be put in 'cut3DSuf' out parameter.
10624 * \param [in] cut3DCurve input paramter that gives for each 3DCurve cell if it owns fully to the plane or partially.
10625 * \param [out] nodesOnPlane, returns all the nodes that are on the plane.
10626 * \param [in] nodal3DSurf is the nodal connectivity of 3D surf mesh.
10627 * \param [in] nodalIndx3DSurf is the nodal connectivity index of 3D surf mesh.
10628 * \param [in] nodal3DCurve is the nodal connectivity of 3D curve mesh.
10629 * \param [in] nodal3DIndxCurve is the nodal connectivity index of 3D curve mesh.
10630 * \param [in] desc is the descending connectivity 3DSurf->3DCurve
10631 * \param [in] descIndx is the descending connectivity index 3DSurf->3DCurve
10632 * \param [out] cut3DSuf input/output param.
10634 void MEDCouplingUMesh::AssemblyForSplitFrom3DCurve(const std::vector<int>& cut3DCurve, std::vector<int>& nodesOnPlane, const int *nodal3DSurf, const int *nodalIndx3DSurf,
10635 const int *nodal3DCurve, const int *nodalIndx3DCurve,
10636 const int *desc, const int *descIndx,
10637 std::vector< std::pair<int,int> >& cut3DSurf)
10639 std::set<int> nodesOnP(nodesOnPlane.begin(),nodesOnPlane.end());
10640 int nbOf3DSurfCell=(int)cut3DSurf.size();
10641 for(int i=0;i<nbOf3DSurfCell;i++)
10643 std::vector<int> res;
10644 int offset=descIndx[i];
10645 int nbOfSeg=descIndx[i+1]-offset;
10646 for(int j=0;j<nbOfSeg;j++)
10648 int edgeId=desc[offset+j];
10649 int status=cut3DCurve[edgeId];
10653 res.push_back(status);
10656 res.push_back(nodal3DCurve[nodalIndx3DCurve[edgeId]+1]);
10657 res.push_back(nodal3DCurve[nodalIndx3DCurve[edgeId]+2]);
10665 cut3DSurf[i].first=res[0]; cut3DSurf[i].second=res[1];
10671 std::set<int> s1(nodal3DSurf+nodalIndx3DSurf[i]+1,nodal3DSurf+nodalIndx3DSurf[i+1]);
10672 std::set_intersection(nodesOnP.begin(),nodesOnP.end(),s1.begin(),s1.end(),std::back_insert_iterator< std::vector<int> >(res));
10675 cut3DSurf[i].first=res[0]; cut3DSurf[i].second=res[1];
10679 cut3DSurf[i].first=-1; cut3DSurf[i].second=-1;
10684 {// case when plane is on a multi colinear edge of a polyhedron
10685 if((int)res.size()==2*nbOfSeg)
10687 cut3DSurf[i].first=-2; cut3DSurf[i].second=i;
10690 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AssemblyPointsFrom3DCurve : unexpected situation !");
10697 * \a this is expected to be a mesh with spaceDim==3 and meshDim==3. If not an exception will be thrown.
10698 * 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).
10699 * 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
10700 * with a plane. The result will be put in 'nodalRes' 'nodalResIndx' and 'cellIds' out parameters.
10701 * \param cut3DSurf input paramter that gives for each 3DSurf its intersection with plane (result of MEDCouplingUMesh::AssemblyForSplitFrom3DCurve).
10702 * \param desc is the descending connectivity 3D->3DSurf
10703 * \param descIndx is the descending connectivity index 3D->3DSurf
10705 void MEDCouplingUMesh::assemblyForSplitFrom3DSurf(const std::vector< std::pair<int,int> >& cut3DSurf,
10706 const int *desc, const int *descIndx,
10707 DataArrayInt *nodalRes, DataArrayInt *nodalResIndx, DataArrayInt *cellIds) const
10709 checkFullyDefined();
10710 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
10711 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::assemblyForSplitFrom3DSurf works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
10712 const int *nodal3D=_nodal_connec->getConstPointer();
10713 const int *nodalIndx3D=_nodal_connec_index->getConstPointer();
10714 int nbOfCells=getNumberOfCells();
10715 for(int i=0;i<nbOfCells;i++)
10717 std::map<int, std::set<int> > m;
10718 int offset=descIndx[i];
10719 int nbOfFaces=descIndx[i+1]-offset;
10722 for(int j=0;j<nbOfFaces;j++)
10724 const std::pair<int,int>& p=cut3DSurf[desc[offset+j]];
10725 if(p.first!=-1 && p.second!=-1)
10729 start=p.first; end=p.second;
10730 m[p.first].insert(p.second);
10731 m[p.second].insert(p.first);
10735 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodal3D[nodalIndx3D[i]]);
10736 int sz=nodalIndx3D[i+1]-nodalIndx3D[i]-1;
10737 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
10738 INTERP_KERNEL::NormalizedCellType cmsId;
10739 unsigned nbOfNodesSon=cm.fillSonCellNodalConnectivity2(j,nodal3D+nodalIndx3D[i]+1,sz,tmp,cmsId);
10740 start=tmp[0]; end=tmp[nbOfNodesSon-1];
10741 for(unsigned k=0;k<nbOfNodesSon;k++)
10743 m[tmp[k]].insert(tmp[(k+1)%nbOfNodesSon]);
10744 m[tmp[(k+1)%nbOfNodesSon]].insert(tmp[k]);
10751 std::vector<int> conn(1,(int)INTERP_KERNEL::NORM_POLYGON);
10755 std::map<int, std::set<int> >::const_iterator it=m.find(start);
10756 const std::set<int>& s=(*it).second;
10757 std::set<int> s2; s2.insert(prev);
10759 std::set_difference(s.begin(),s.end(),s2.begin(),s2.end(),inserter(s3,s3.begin()));
10762 int val=*s3.begin();
10763 conn.push_back(start);
10770 conn.push_back(end);
10773 nodalRes->insertAtTheEnd(conn.begin(),conn.end());
10774 nodalResIndx->pushBackSilent(nodalRes->getNumberOfTuples());
10775 cellIds->pushBackSilent(i);
10781 * 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
10782 * 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
10783 * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
10784 * 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
10785 * 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.
10787 * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
10789 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const int *nodalConnBg, const int *nodalConnEnd, DataArrayInt *nodalConnecOut)
10791 std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
10794 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
10795 if(cm.getDimension()==2)
10797 const int *node=nodalConnBg+1;
10798 int startNode=*node++;
10799 double refX=coords[2*startNode];
10800 for(;node!=nodalConnEnd;node++)
10802 if(coords[2*(*node)]<refX)
10805 refX=coords[2*startNode];
10808 std::vector<int> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
10812 double angle0=-M_PI/2;
10817 double angleNext=0.;
10818 while(nextNode!=startNode)
10822 for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
10824 if(*node!=tmpOut.back() && *node!=prevNode)
10826 tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
10827 double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
10832 res=angle0-angleM+2.*M_PI;
10841 if(nextNode!=startNode)
10843 angle0=angleNext-M_PI;
10846 prevNode=tmpOut.back();
10847 tmpOut.push_back(nextNode);
10850 std::vector<int> tmp3(2*(sz-1));
10851 std::vector<int>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
10852 std::copy(nodalConnBg+1,nodalConnEnd,it);
10853 if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
10855 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
10858 if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
10860 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
10865 nodalConnecOut->pushBackSilent((int)INTERP_KERNEL::NORM_POLYGON);
10866 nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
10871 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
10874 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
10878 * This method works on an input pair (\b arr, \b arrIndx) where \b arr indexes is in \b arrIndx.
10879 * 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.
10881 * \param [in] idsToRemoveBg begin of set of ids to remove in \b arr (included)
10882 * \param [in] idsToRemoveEnd end of set of ids to remove in \b arr (excluded)
10883 * \param [in,out] arr array in which the remove operation will be done.
10884 * \param [in,out] arrIndx array in the remove operation will modify
10885 * \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])
10886 * \return true if \b arr and \b arrIndx have been modified, false if not.
10888 bool MEDCouplingUMesh::RemoveIdsFromIndexedArrays(const int *idsToRemoveBg, const int *idsToRemoveEnd, DataArrayInt *arr, DataArrayInt *arrIndx, int offsetForRemoval)
10890 if(!arrIndx || !arr)
10891 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : some input arrays are empty !");
10892 if(offsetForRemoval<0)
10893 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : offsetForRemoval should be >=0 !");
10894 std::set<int> s(idsToRemoveBg,idsToRemoveEnd);
10895 int nbOfGrps=arrIndx->getNumberOfTuples()-1;
10896 int *arrIPtr=arrIndx->getPointer();
10898 int previousArrI=0;
10899 const int *arrPtr=arr->getConstPointer();
10900 std::vector<int> arrOut;//no utility to switch to DataArrayInt because copy always needed
10901 for(int i=0;i<nbOfGrps;i++,arrIPtr++)
10903 if(*arrIPtr-previousArrI>offsetForRemoval)
10905 for(const int *work=arrPtr+previousArrI+offsetForRemoval;work!=arrPtr+*arrIPtr;work++)
10907 if(s.find(*work)==s.end())
10908 arrOut.push_back(*work);
10911 previousArrI=*arrIPtr;
10912 *arrIPtr=(int)arrOut.size();
10914 if(arr->getNumberOfTuples()==(int)arrOut.size())
10916 arr->alloc((int)arrOut.size(),1);
10917 std::copy(arrOut.begin(),arrOut.end(),arr->getPointer());
10922 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
10923 * (\ref numbering-indirect).
10924 * This method returns the result of the extraction ( specified by a set of ids in [\b idsOfSelectBg , \b idsOfSelectEnd ) ).
10925 * The selection of extraction is done standardly in new2old format.
10926 * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
10928 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
10929 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
10930 * \param [in] arrIn arr origin array from which the extraction will be done.
10931 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
10932 * \param [out] arrOut the resulting array
10933 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
10934 * \sa MEDCouplingUMesh::ExtractFromIndexedArraysSlice
10936 void MEDCouplingUMesh::ExtractFromIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
10937 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
10939 if(!arrIn || !arrIndxIn)
10940 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input pointer is NULL !");
10941 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
10942 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
10943 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input arrays must have exactly one component !");
10944 std::size_t sz=std::distance(idsOfSelectBg,idsOfSelectEnd);
10945 const int *arrInPtr=arrIn->getConstPointer();
10946 const int *arrIndxPtr=arrIndxIn->getConstPointer();
10947 int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
10949 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
10950 int maxSizeOfArr=arrIn->getNumberOfTuples();
10951 MCAuto<DataArrayInt> arro=DataArrayInt::New();
10952 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
10953 arrIo->alloc((int)(sz+1),1);
10954 const int *idsIt=idsOfSelectBg;
10955 int *work=arrIo->getPointer();
10958 for(std::size_t i=0;i<sz;i++,work++,idsIt++)
10960 if(*idsIt>=0 && *idsIt<nbOfGrps)
10961 lgth+=arrIndxPtr[*idsIt+1]-arrIndxPtr[*idsIt];
10964 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " ! Must be in [0," << nbOfGrps << ") !";
10965 throw INTERP_KERNEL::Exception(oss.str().c_str());
10971 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " and at this pos arrIndxIn[" << *idsIt;
10972 oss << "+1]-arrIndxIn[" << *idsIt << "] < 0 ! The input index array is bugged !";
10973 throw INTERP_KERNEL::Exception(oss.str().c_str());
10976 arro->alloc(lgth,1);
10977 work=arro->getPointer();
10978 idsIt=idsOfSelectBg;
10979 for(std::size_t i=0;i<sz;i++,idsIt++)
10981 if(arrIndxPtr[*idsIt]>=0 && arrIndxPtr[*idsIt+1]<=maxSizeOfArr)
10982 work=std::copy(arrInPtr+arrIndxPtr[*idsIt],arrInPtr+arrIndxPtr[*idsIt+1],work);
10985 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " arrIndx[" << *idsIt << "] must be >= 0 and arrIndx[";
10986 oss << *idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
10987 throw INTERP_KERNEL::Exception(oss.str().c_str());
10990 arrOut=arro.retn();
10991 arrIndexOut=arrIo.retn();
10995 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
10996 * (\ref numbering-indirect).
10997 * 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 ).
10998 * The selection of extraction is done standardly in new2old format.
10999 * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
11001 * \param [in] idsOfSelectStart begin of set of ids of the input extraction (included)
11002 * \param [in] idsOfSelectStop end of set of ids of the input extraction (excluded)
11003 * \param [in] idsOfSelectStep
11004 * \param [in] arrIn arr origin array from which the extraction will be done.
11005 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11006 * \param [out] arrOut the resulting array
11007 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11008 * \sa MEDCouplingUMesh::ExtractFromIndexedArrays
11010 void MEDCouplingUMesh::ExtractFromIndexedArraysSlice(int idsOfSelectStart, int idsOfSelectStop, int idsOfSelectStep, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11011 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11013 if(!arrIn || !arrIndxIn)
11014 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input pointer is NULL !");
11015 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
11016 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
11017 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input arrays must have exactly one component !");
11018 int sz=DataArrayInt::GetNumberOfItemGivenBESRelative(idsOfSelectStart,idsOfSelectStop,idsOfSelectStep,"MEDCouplingUMesh::ExtractFromIndexedArraysSlice : Input slice ");
11019 const int *arrInPtr=arrIn->getConstPointer();
11020 const int *arrIndxPtr=arrIndxIn->getConstPointer();
11021 int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
11023 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
11024 int maxSizeOfArr=arrIn->getNumberOfTuples();
11025 MCAuto<DataArrayInt> arro=DataArrayInt::New();
11026 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11027 arrIo->alloc((int)(sz+1),1);
11028 int idsIt=idsOfSelectStart;
11029 int *work=arrIo->getPointer();
11032 for(int i=0;i<sz;i++,work++,idsIt+=idsOfSelectStep)
11034 if(idsIt>=0 && idsIt<nbOfGrps)
11035 lgth+=arrIndxPtr[idsIt+1]-arrIndxPtr[idsIt];
11038 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " ! Must be in [0," << nbOfGrps << ") !";
11039 throw INTERP_KERNEL::Exception(oss.str().c_str());
11045 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " and at this pos arrIndxIn[" << idsIt;
11046 oss << "+1]-arrIndxIn[" << idsIt << "] < 0 ! The input index array is bugged !";
11047 throw INTERP_KERNEL::Exception(oss.str().c_str());
11050 arro->alloc(lgth,1);
11051 work=arro->getPointer();
11052 idsIt=idsOfSelectStart;
11053 for(int i=0;i<sz;i++,idsIt+=idsOfSelectStep)
11055 if(arrIndxPtr[idsIt]>=0 && arrIndxPtr[idsIt+1]<=maxSizeOfArr)
11056 work=std::copy(arrInPtr+arrIndxPtr[idsIt],arrInPtr+arrIndxPtr[idsIt+1],work);
11059 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " arrIndx[" << idsIt << "] must be >= 0 and arrIndx[";
11060 oss << idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
11061 throw INTERP_KERNEL::Exception(oss.str().c_str());
11064 arrOut=arro.retn();
11065 arrIndexOut=arrIo.retn();
11069 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11070 * 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
11071 * cellIds \b in [ \b idsOfSelectBg , \b idsOfSelectEnd ) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
11072 * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
11074 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
11075 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
11076 * \param [in] arrIn arr origin array from which the extraction will be done.
11077 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11078 * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg, \b idsOfSelectEnd )
11079 * \param [in] srcArrIndex index array of \b srcArr
11080 * \param [out] arrOut the resulting array
11081 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11083 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
11085 void MEDCouplingUMesh::SetPartOfIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11086 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
11087 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11089 if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11090 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArrays : presence of null pointer in input parameter !");
11091 MCAuto<DataArrayInt> arro=DataArrayInt::New();
11092 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11093 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11094 std::vector<bool> v(nbOfTuples,true);
11096 const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11097 const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11098 for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
11100 if(*it>=0 && *it<nbOfTuples)
11103 offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[*it+1]-arrIndxInPtr[*it]);
11107 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArrays : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
11108 throw INTERP_KERNEL::Exception(oss.str().c_str());
11111 srcArrIndexPtr=srcArrIndex->getConstPointer();
11112 arrIo->alloc(nbOfTuples+1,1);
11113 arro->alloc(arrIn->getNumberOfTuples()+offset,1);
11114 const int *arrInPtr=arrIn->getConstPointer();
11115 const int *srcArrPtr=srcArr->getConstPointer();
11116 int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
11117 int *arroPtr=arro->getPointer();
11118 for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
11122 arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
11123 *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
11127 std::size_t pos=std::distance(idsOfSelectBg,std::find(idsOfSelectBg,idsOfSelectEnd,ii));
11128 arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
11129 *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
11132 arrOut=arro.retn();
11133 arrIndexOut=arrIo.retn();
11137 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11138 * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
11140 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
11141 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
11142 * \param [in,out] arrInOut arr origin array from which the extraction will be done.
11143 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11144 * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg , \b idsOfSelectEnd )
11145 * \param [in] srcArrIndex index array of \b srcArr
11147 * \sa MEDCouplingUMesh::SetPartOfIndexedArrays
11149 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(const int *idsOfSelectBg, const int *idsOfSelectEnd, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
11150 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
11152 if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11153 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : presence of null pointer in input parameter !");
11154 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11155 const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11156 const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11157 int *arrInOutPtr=arrInOut->getPointer();
11158 const int *srcArrPtr=srcArr->getConstPointer();
11159 for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
11161 if(*it>=0 && *it<nbOfTuples)
11163 if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[*it+1]-arrIndxInPtr[*it])
11164 std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[*it]);
11167 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] !";
11168 throw INTERP_KERNEL::Exception(oss.str().c_str());
11173 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
11174 throw INTERP_KERNEL::Exception(oss.str().c_str());
11180 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
11181 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
11182 * 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]].
11183 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
11184 * A negative value in \b arrIn means that it is ignored.
11185 * 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.
11187 * \param [in] arrIn arr origin array from which the extraction will be done.
11188 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11189 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
11190 * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
11192 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn)
11194 int seed=0,nbOfDepthPeelingPerformed=0;
11195 return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
11199 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
11200 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
11201 * 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]].
11202 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
11203 * A negative value in \b arrIn means that it is ignored.
11204 * 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.
11205 * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
11206 * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
11207 * \param [in] arrIn arr origin array from which the extraction will be done.
11208 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11209 * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
11210 * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
11211 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
11212 * \sa MEDCouplingUMesh::partitionBySpreadZone
11214 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed)
11216 nbOfDepthPeelingPerformed=0;
11218 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
11219 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11222 DataArrayInt *ret=DataArrayInt::New(); ret->alloc(0,1);
11226 std::vector<bool> fetched(nbOfTuples,false);
11227 return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
11230 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg(std::vector<bool>& fetched, const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed)
11232 nbOfDepthPeelingPerformed=0;
11233 if(!seedBg || !seedEnd || !arrIn || !arrIndxIn)
11234 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg : some input pointer is NULL !");
11235 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11236 std::vector<bool> fetched2(nbOfTuples,false);
11238 for(const int *seedElt=seedBg;seedElt!=seedEnd;seedElt++,i++)
11240 if(*seedElt>=0 && *seedElt<nbOfTuples)
11241 { fetched[*seedElt]=true; fetched2[*seedElt]=true; }
11243 { 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()); }
11245 const int *arrInPtr=arrIn->getConstPointer();
11246 const int *arrIndxPtr=arrIndxIn->getConstPointer();
11247 int targetNbOfDepthPeeling=nbOfDepthPeeling!=-1?nbOfDepthPeeling:std::numeric_limits<int>::max();
11248 std::vector<int> idsToFetch1(seedBg,seedEnd);
11249 std::vector<int> idsToFetch2;
11250 std::vector<int> *idsToFetch=&idsToFetch1;
11251 std::vector<int> *idsToFetchOther=&idsToFetch2;
11252 while(!idsToFetch->empty() && nbOfDepthPeelingPerformed<targetNbOfDepthPeeling)
11254 for(std::vector<int>::const_iterator it=idsToFetch->begin();it!=idsToFetch->end();it++)
11255 for(const int *it2=arrInPtr+arrIndxPtr[*it];it2!=arrInPtr+arrIndxPtr[*it+1];it2++)
11257 { fetched[*it2]=true; fetched2[*it2]=true; idsToFetchOther->push_back(*it2); }
11258 std::swap(idsToFetch,idsToFetchOther);
11259 idsToFetchOther->clear();
11260 nbOfDepthPeelingPerformed++;
11262 int lgth=(int)std::count(fetched2.begin(),fetched2.end(),true);
11264 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(lgth,1);
11265 int *retPtr=ret->getPointer();
11266 for(std::vector<bool>::const_iterator it=fetched2.begin();it!=fetched2.end();it++,i++)
11273 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11274 * 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
11275 * cellIds \b in [\b idsOfSelectBg, \b idsOfSelectEnd) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
11276 * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
11278 * \param [in] start begin of set of ids of the input extraction (included)
11279 * \param [in] end end of set of ids of the input extraction (excluded)
11280 * \param [in] step step of the set of ids in range mode.
11281 * \param [in] arrIn arr origin array from which the extraction will be done.
11282 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11283 * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
11284 * \param [in] srcArrIndex index array of \b srcArr
11285 * \param [out] arrOut the resulting array
11286 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11288 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx MEDCouplingUMesh::SetPartOfIndexedArrays
11290 void MEDCouplingUMesh::SetPartOfIndexedArraysSlice(int start, int end, int step, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11291 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
11292 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11294 if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11295 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSlice : presence of null pointer in input parameter !");
11296 MCAuto<DataArrayInt> arro=DataArrayInt::New();
11297 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11298 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11300 const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11301 const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11302 int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSlice : ");
11304 for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
11306 if(it>=0 && it<nbOfTuples)
11307 offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[it+1]-arrIndxInPtr[it]);
11310 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
11311 throw INTERP_KERNEL::Exception(oss.str().c_str());
11314 srcArrIndexPtr=srcArrIndex->getConstPointer();
11315 arrIo->alloc(nbOfTuples+1,1);
11316 arro->alloc(arrIn->getNumberOfTuples()+offset,1);
11317 const int *arrInPtr=arrIn->getConstPointer();
11318 const int *srcArrPtr=srcArr->getConstPointer();
11319 int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
11320 int *arroPtr=arro->getPointer();
11321 for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
11323 int pos=DataArray::GetPosOfItemGivenBESRelativeNoThrow(ii,start,end,step);
11326 arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
11327 *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
11331 arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
11332 *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
11335 arrOut=arro.retn();
11336 arrIndexOut=arrIo.retn();
11340 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11341 * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
11343 * \param [in] start begin of set of ids of the input extraction (included)
11344 * \param [in] end end of set of ids of the input extraction (excluded)
11345 * \param [in] step step of the set of ids in range mode.
11346 * \param [in,out] arrInOut arr origin array from which the extraction will be done.
11347 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11348 * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
11349 * \param [in] srcArrIndex index array of \b srcArr
11351 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSlice MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
11353 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(int start, int end, int step, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
11354 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
11356 if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11357 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : presence of null pointer in input parameter !");
11358 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11359 const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11360 const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11361 int *arrInOutPtr=arrInOut->getPointer();
11362 const int *srcArrPtr=srcArr->getConstPointer();
11363 int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : ");
11365 for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
11367 if(it>=0 && it<nbOfTuples)
11369 if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[it+1]-arrIndxInPtr[it])
11370 std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[it]);
11373 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " id (idsOfSelectBg[" << i << "]) is " << it << " arrIndxIn[id+1]-arrIndxIn[id]!=srcArrIndex[pos+1]-srcArrIndex[pos] !";
11374 throw INTERP_KERNEL::Exception(oss.str().c_str());
11379 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
11380 throw INTERP_KERNEL::Exception(oss.str().c_str());
11386 * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
11387 * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
11388 * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
11389 * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
11390 * The sum of measure field of returned mesh is equal to the sum of measure field of this.
11392 * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
11394 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
11396 checkFullyDefined();
11397 int mdim=getMeshDimension();
11398 int spaceDim=getSpaceDimension();
11400 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
11401 std::vector<DataArrayInt *> partition=partitionBySpreadZone();
11402 std::vector< MCAuto<DataArrayInt> > partitionAuto; partitionAuto.reserve(partition.size());
11403 std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayInt> > >(partitionAuto));
11404 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
11405 ret->setCoords(getCoords());
11406 ret->allocateCells((int)partition.size());
11408 for(std::vector<DataArrayInt *>::const_iterator it=partition.begin();it!=partition.end();it++)
11410 MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
11411 MCAuto<DataArrayInt> cell;
11415 cell=tmp->buildUnionOf2DMesh();
11418 cell=tmp->buildUnionOf3DMesh();
11421 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
11424 ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->getConstPointer()+1);
11427 ret->finishInsertingCells();
11432 * This method partitions \b this into contiguous zone.
11433 * This method only needs a well defined connectivity. Coordinates are not considered here.
11434 * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
11436 std::vector<DataArrayInt *> MEDCouplingUMesh::partitionBySpreadZone() const
11438 int nbOfCellsCur=getNumberOfCells();
11439 std::vector<DataArrayInt *> ret;
11440 if(nbOfCellsCur<=0)
11442 DataArrayInt *neigh=0,*neighI=0;
11443 computeNeighborsOfCells(neigh,neighI);
11444 MCAuto<DataArrayInt> neighAuto(neigh),neighIAuto(neighI);
11445 std::vector<bool> fetchedCells(nbOfCellsCur,false);
11446 std::vector< MCAuto<DataArrayInt> > ret2;
11448 while(seed<nbOfCellsCur)
11450 int nbOfPeelPerformed=0;
11451 ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,neigh,neighI,-1,nbOfPeelPerformed));
11452 seed=(int)std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false));
11454 for(std::vector< MCAuto<DataArrayInt> >::iterator it=ret2.begin();it!=ret2.end();it++)
11455 ret.push_back((*it).retn());
11460 * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
11461 * newly allocated DataArrayInt instance with 2 components ready to be interpreted as input of DataArrayInt::findRangeIdForEachTuple method.
11463 * \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.
11464 * \return a newly allocated DataArrayInt to be managed by the caller.
11465 * \throw In case of \a code has not the right format (typically of size 3*n)
11467 DataArrayInt *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<int>& code)
11469 MCAuto<DataArrayInt> ret=DataArrayInt::New();
11470 std::size_t nb=code.size()/3;
11471 if(code.size()%3!=0)
11472 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
11473 ret->alloc((int)nb,2);
11474 int *retPtr=ret->getPointer();
11475 for(std::size_t i=0;i<nb;i++,retPtr+=2)
11477 retPtr[0]=code[3*i+2];
11478 retPtr[1]=code[3*i+2]+code[3*i+1];
11484 * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
11485 * All cells in \a this are expected to be linear 3D cells.
11486 * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
11487 * It leads to an increase to number of cells.
11488 * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
11489 * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
11490 * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
11492 * \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.
11493 * For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
11494 * \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.
11495 * \param [out] n2oCells - A new instance of DataArrayInt holding, for each new cell,
11496 * an id of old cell producing it. The caller is to delete this array using
11497 * decrRef() as it is no more needed.
11498 * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
11500 * \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
11501 * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
11503 * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
11504 * \throw If \a this is not fully constituted with linear 3D cells.
11505 * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
11507 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayInt *& n2oCells, int& nbOfAdditionalPoints) const
11509 INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
11510 checkConnectivityFullyDefined();
11511 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
11512 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
11513 int nbOfCells(getNumberOfCells()),nbNodes(getNumberOfNodes());
11514 MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
11515 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfCells,1);
11516 int *retPt(ret->getPointer());
11517 MCAuto<DataArrayInt> newConn(DataArrayInt::New()); newConn->alloc(0,1);
11518 MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
11519 const int *oldc(_nodal_connec->begin());
11520 const int *oldci(_nodal_connec_index->begin());
11521 const double *coords(_coords->begin());
11522 for(int i=0;i<nbOfCells;i++,oldci++,retPt++)
11524 std::vector<int> a; std::vector<double> b;
11525 INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
11526 std::size_t nbOfTet(a.size()/4); *retPt=(int)nbOfTet;
11527 const int *aa(&a[0]);
11530 for(std::vector<int>::iterator it=a.begin();it!=a.end();it++)
11532 *it=(-(*(it))-1+nbNodes);
11533 addPts->insertAtTheEnd(b.begin(),b.end());
11534 nbNodes+=(int)b.size()/3;
11536 for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
11537 newConn->insertAtTheEnd(aa,aa+4);
11539 if(!addPts->empty())
11541 addPts->rearrange(3);
11542 nbOfAdditionalPoints=addPts->getNumberOfTuples();
11543 addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
11544 ret0->setCoords(addPts);
11548 nbOfAdditionalPoints=0;
11549 ret0->setCoords(getCoords());
11551 ret0->setNodalConnectivity(newConn);
11553 ret->computeOffsetsFull();
11554 n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
11555 return ret0.retn();
11559 * 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).
11561 * \sa MEDCouplingUMesh::split2DCells
11563 void MEDCouplingUMesh::split2DCellsLinear(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI)
11565 checkConnectivityFullyDefined();
11566 int ncells(getNumberOfCells()),lgthToReach(getNodalConnectivityArrayLen()+subNodesInSeg->getNumberOfTuples());
11567 MCAuto<DataArrayInt> c(DataArrayInt::New()); c->alloc((std::size_t)lgthToReach);
11568 const int *subPtr(subNodesInSeg->begin()),*subIPtr(subNodesInSegI->begin()),*descPtr(desc->begin()),*descIPtr(descI->begin()),*oldConn(getNodalConnectivity()->begin());
11569 int *cPtr(c->getPointer()),*ciPtr(getNodalConnectivityIndex()->getPointer());
11570 int prevPosOfCi(ciPtr[0]);
11571 for(int i=0;i<ncells;i++,ciPtr++,descIPtr++)
11573 int offset(descIPtr[0]),sz(descIPtr[1]-descIPtr[0]),deltaSz(0);
11574 *cPtr++=(int)INTERP_KERNEL::NORM_POLYGON; *cPtr++=oldConn[prevPosOfCi+1];
11575 for(int j=0;j<sz;j++)
11577 int offset2(subIPtr[descPtr[offset+j]]),sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]);
11578 for(int k=0;k<sz2;k++)
11579 *cPtr++=subPtr[offset2+k];
11581 *cPtr++=oldConn[prevPosOfCi+j+2];
11584 prevPosOfCi=ciPtr[1];
11585 ciPtr[1]=ciPtr[0]+1+sz+deltaSz;//sz==old nb of nodes because (nb of subedges=nb of nodes for polygons)
11588 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCellsLinear : Some of edges to be split are orphan !");
11589 _nodal_connec->decrRef();
11590 _nodal_connec=c.retn(); _types.clear(); _types.insert(INTERP_KERNEL::NORM_POLYGON);
11593 int InternalAddPoint(const INTERP_KERNEL::Edge *e, int id, const double *coo, int startId, int endId, DataArrayDouble& addCoo, int& nodesCnter)
11599 int ret(nodesCnter++);
11601 e->getMiddleOfPoints(coo+2*startId,coo+2*endId,newPt);
11602 addCoo.insertAtTheEnd(newPt,newPt+2);
11607 int InternalAddPointOriented(const INTERP_KERNEL::Edge *e, int id, const double *coo, int startId, int endId, DataArrayDouble& addCoo, int& nodesCnter)
11613 int ret(nodesCnter++);
11615 e->getMiddleOfPointsOriented(coo+2*startId,coo+2*endId,newPt);
11616 addCoo.insertAtTheEnd(newPt,newPt+2);
11624 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)
11627 int trueStart(start>=0?start:nbOfEdges+start);
11628 tmp[0]=linOrArc?(int)INTERP_KERNEL::NORM_QPOLYG:(int)INTERP_KERNEL::NORM_POLYGON; tmp[1]=connBg[trueStart]; tmp[2]=connBg[stp];
11629 newConnOfCell->insertAtTheEnd(tmp,tmp+3);
11634 int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11635 InternalAddPointOriented(e,-1,coords,tmp[1],tmp[2],*appendedCoords,tmp2);
11636 middles.push_back(tmp3+offset);
11639 middles.push_back(connBg[trueStart+nbOfEdges]);
11643 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)
11645 int tmpSrt(newConnOfCell->back()),tmpEnd(connBg[stp]);
11646 newConnOfCell->pushBackSilent(tmpEnd);
11651 int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11652 InternalAddPointOriented(e,-1,coords,tmpSrt,tmpEnd,*appendedCoords,tmp2);
11653 middles.push_back(tmp3+offset);
11656 middles.push_back(connBg[start+nbOfEdges]);
11660 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)
11662 // only the quadratic point to deal with:
11667 int tmpSrt(connBg[start]),tmpEnd(connBg[stp]);
11668 int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11669 InternalAddPointOriented(e,-1,coords,tmpSrt,tmpEnd,*appendedCoords,tmp2);
11670 middles.push_back(tmp3+offset);
11673 middles.push_back(connBg[start+nbOfEdges]);
11680 * 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 ) .
11681 * \a appendedCoords is a DataArrayDouble instance with number of components equal to one (even if the items are pushed by pair).
11683 bool MEDCouplingUMesh::Colinearize2DCell(const double *coords, const int *connBg, const int *connEnd, int offset, DataArrayInt *newConnOfCell, DataArrayDouble *appendedCoords)
11685 std::size_t sz(std::distance(connBg,connEnd));
11686 if(sz<3)//3 because 2+1(for the cell type) and 2 is the minimal number of edges of 2D cell.
11687 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Colinearize2DCell : the input cell has invalid format !");
11689 INTERP_KERNEL::AutoPtr<int> tmpConn(new int[sz]);
11690 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connBg[0]));
11691 unsigned nbs(cm.getNumberOfSons2(connBg+1,sz));
11692 unsigned nbOfHit(0); // number of fusions operated
11693 int posBaseElt(0),posEndElt(0),nbOfTurn(0);
11694 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
11695 INTERP_KERNEL::NormalizedCellType typeOfSon;
11696 std::vector<int> middles;
11698 for(;(nbOfTurn+nbOfHit)<nbs;nbOfTurn++)
11700 cm.fillSonCellNodalConnectivity2(posBaseElt,connBg+1,sz,tmpConn,typeOfSon);
11701 std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
11702 INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11703 posEndElt = posBaseElt+1;
11705 // Look backward first: are the final edges of the cells colinear with the first ones?
11706 // This initializes posBaseElt.
11709 for(unsigned i=1;i<nbs && nbOfHit<maxNbOfHit;i++) // 2nd condition is to avoid ending with a cell wih one single edge
11711 cm.fillSonCellNodalConnectivity2(nbs-i,connBg+1,sz,tmpConn,typeOfSon);
11712 INTERP_KERNEL::Edge *eCand(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11713 INTERP_KERNEL::EdgeIntersector *eint(INTERP_KERNEL::Edge::BuildIntersectorWith(e,eCand));
11714 bool isColinear=eint->areColinears();
11727 // Now move forward:
11728 const unsigned fwdStart = (nbOfTurn == 0 ? 0 : posBaseElt); // the first element to be inspected going forward
11729 for(unsigned j=fwdStart+1;j<nbs && nbOfHit<maxNbOfHit;j++) // 2nd condition is to avoid ending with a cell wih one single edge
11731 cm.fillSonCellNodalConnectivity2((int)j,connBg+1,sz,tmpConn,typeOfSon); // get edge #j's connectivity
11732 INTERP_KERNEL::Edge *eCand(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11733 INTERP_KERNEL::EdgeIntersector *eint(INTERP_KERNEL::Edge::BuildIntersectorWith(e,eCand));
11734 bool isColinear(eint->areColinears());
11746 //push [posBaseElt,posEndElt) in newConnOfCell using e
11747 // 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!
11749 // at the begining of the connectivity (insert type)
11750 EnterTheResultOf2DCellFirst(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
11751 else if((nbOfHit+nbOfTurn) != (nbs-1))
11753 EnterTheResultOf2DCellMiddle(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
11754 if ((nbOfHit+nbOfTurn) == (nbs-1))
11755 // at the end (only quad points to deal with)
11756 EnterTheResultOf2DCellEnd(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
11757 posBaseElt=posEndElt;
11760 if(!middles.empty())
11761 newConnOfCell->insertAtTheEnd(middles.begin(),middles.end());
11766 * It is the quadratic part of MEDCouplingUMesh::split2DCells. Here some additionnal nodes can be added at the end of coordinates array object.
11768 * \return int - the number of new nodes created.
11769 * \sa MEDCouplingUMesh::split2DCells
11771 int MEDCouplingUMesh::split2DCellsQuadratic(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *mid, const DataArrayInt *midI)
11773 checkConsistencyLight();
11774 int ncells(getNumberOfCells()),lgthToReach(getNodalConnectivityArrayLen()+2*subNodesInSeg->getNumberOfTuples()),nodesCnt(getNumberOfNodes());
11775 MCAuto<DataArrayInt> c(DataArrayInt::New()); c->alloc((std::size_t)lgthToReach);
11776 MCAuto<DataArrayDouble> addCoo(DataArrayDouble::New()); addCoo->alloc(0,1);
11777 const int *subPtr(subNodesInSeg->begin()),*subIPtr(subNodesInSegI->begin()),*descPtr(desc->begin()),*descIPtr(descI->begin()),*oldConn(getNodalConnectivity()->begin());
11778 const int *midPtr(mid->begin()),*midIPtr(midI->begin());
11779 const double *oldCoordsPtr(getCoords()->begin());
11780 int *cPtr(c->getPointer()),*ciPtr(getNodalConnectivityIndex()->getPointer());
11781 int prevPosOfCi(ciPtr[0]);
11782 for(int i=0;i<ncells;i++,ciPtr++,descIPtr++)
11784 int offset(descIPtr[0]),sz(descIPtr[1]-descIPtr[0]),deltaSz(sz);
11785 for(int j=0;j<sz;j++)
11786 { int sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]); deltaSz+=sz2; }
11787 *cPtr++=(int)INTERP_KERNEL::NORM_QPOLYG; cPtr[0]=oldConn[prevPosOfCi+1];
11788 for(int j=0;j<sz;j++)//loop over subedges of oldConn
11790 int offset2(subIPtr[descPtr[offset+j]]),sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]),offset3(midIPtr[descPtr[offset+j]]);
11794 cPtr[1]=oldConn[prevPosOfCi+2+j];
11795 cPtr[deltaSz]=oldConn[prevPosOfCi+1+j+sz]; cPtr++;
11798 std::vector<INTERP_KERNEL::Node *> ns(3);
11799 ns[0]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+j]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+j]+1]);
11800 ns[1]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+(1+j)%sz]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+(1+j)%sz]+1]);
11801 ns[2]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+sz+j]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+sz+j]+1]);
11802 MCAuto<INTERP_KERNEL::Edge> e(INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(ns));
11803 for(int k=0;k<sz2;k++)//loop over subsplit of current subedge
11805 cPtr[1]=subPtr[offset2+k];
11806 cPtr[deltaSz]=InternalAddPoint(e,midPtr[offset3+k],oldCoordsPtr,cPtr[0],cPtr[1],*addCoo,nodesCnt); cPtr++;
11808 int tmpEnd(oldConn[prevPosOfCi+1+(j+1)%sz]);
11810 { cPtr[1]=tmpEnd; }
11811 cPtr[deltaSz]=InternalAddPoint(e,midPtr[offset3+sz2],oldCoordsPtr,cPtr[0],tmpEnd,*addCoo,nodesCnt); cPtr++;
11813 prevPosOfCi=ciPtr[1]; cPtr+=deltaSz;
11814 ciPtr[1]=ciPtr[0]+1+2*deltaSz;//sz==old nb of nodes because (nb of subedges=nb of nodes for polygons)
11817 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCellsQuadratic : Some of edges to be split are orphan !");
11818 _nodal_connec->decrRef();
11819 _nodal_connec=c.retn(); _types.clear(); _types.insert(INTERP_KERNEL::NORM_QPOLYG);
11820 addCoo->rearrange(2);
11821 MCAuto<DataArrayDouble> coo(DataArrayDouble::Aggregate(getCoords(),addCoo));//info are copied from getCoords() by using Aggregate
11823 return addCoo->getNumberOfTuples();
11826 void MEDCouplingUMesh::ComputeAllTypesInternal(std::set<INTERP_KERNEL::NormalizedCellType>& types, const DataArrayInt *nodalConnec, const DataArrayInt *nodalConnecIndex)
11828 if(nodalConnec && nodalConnecIndex)
11831 const int *conn(nodalConnec->getConstPointer()),*connIndex(nodalConnecIndex->getConstPointer());
11832 int nbOfElem(nodalConnecIndex->getNbOfElems()-1);
11834 for(const int *pt=connIndex;pt!=connIndex+nbOfElem;pt++)
11835 types.insert((INTERP_KERNEL::NormalizedCellType)conn[*pt]);
11839 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
11840 _own_cell(true),_cell_id(-1),_nb_cell(0)
11845 _nb_cell=mesh->getNumberOfCells();
11849 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
11857 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_cell(itc),
11858 _own_cell(false),_cell_id(bg-1),
11865 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
11868 if(_cell_id<_nb_cell)
11877 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
11883 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
11885 return new MEDCouplingUMeshCellByTypeIterator(_mesh);
11888 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
11894 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh, INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_type(type),
11902 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
11908 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
11913 int MEDCouplingUMeshCellEntry::getNumberOfElems() const
11918 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
11920 return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
11923 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
11928 _nb_cell=mesh->getNumberOfCells();
11932 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
11939 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
11941 const int *c=_mesh->getNodalConnectivity()->getConstPointer();
11942 const int *ci=_mesh->getNodalConnectivityIndex()->getConstPointer();
11943 if(_cell_id<_nb_cell)
11945 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
11946 int nbOfElems=(int)std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type)));
11947 int startId=_cell_id;
11948 _cell_id+=nbOfElems;
11949 return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
11955 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
11959 _conn=mesh->getNodalConnectivity()->getPointer();
11960 _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
11964 void MEDCouplingUMeshCell::next()
11966 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
11971 _conn_lgth=_conn_indx[1]-_conn_indx[0];
11974 std::string MEDCouplingUMeshCell::repr() const
11976 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
11978 std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
11980 std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<int>(oss," "));
11984 return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
11987 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
11989 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
11990 return (INTERP_KERNEL::NormalizedCellType)_conn[0];
11992 return INTERP_KERNEL::NORM_ERROR;
11995 const int *MEDCouplingUMeshCell::getAllConn(int& lgth) const
11998 if(_conn_lgth!=NOTICABLE_FIRST_VAL)