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 "MEDCouplingCMesh.hxx"
23 #include "MEDCoupling1GTUMesh.hxx"
24 #include "MEDCouplingFieldDouble.hxx"
25 #include "MEDCouplingSkyLineArray.hxx"
26 #include "CellModel.hxx"
27 #include "VolSurfUser.txx"
28 #include "InterpolationUtils.hxx"
29 #include "PointLocatorAlgos.txx"
31 #include "BBTreeDst.txx"
32 #include "SplitterTetra.hxx"
33 #include "DiameterCalculator.hxx"
34 #include "DirectedBoundingBox.hxx"
35 #include "InterpKernelMatrixTools.hxx"
36 #include "InterpKernelMeshQuality.hxx"
37 #include "InterpKernelCellSimplify.hxx"
38 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
39 #include "InterpKernelAutoPtr.hxx"
40 #include "InterpKernelGeo2DNode.hxx"
41 #include "InterpKernelGeo2DEdgeLin.hxx"
42 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
43 #include "InterpKernelGeo2DQuadraticPolygon.hxx"
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 };
58 const int MEDCouplingUMesh::MEDCOUPLING2VTKTYPETRADUCER[INTERP_KERNEL::NORM_MAXTYPE+1]={1,3,21,5,9,7,22,34,23,28,-1,-1,-1,-1,10,14,13,-1,12,-1,24,-1,16,27,-1,26,-1,29,-1,-1,25,42,36,4};
61 MEDCouplingUMesh *MEDCouplingUMesh::New()
63 return new MEDCouplingUMesh;
66 MEDCouplingUMesh *MEDCouplingUMesh::New(const std::string& meshName, int meshDim)
68 MEDCouplingUMesh *ret=new MEDCouplingUMesh;
69 ret->setName(meshName);
70 ret->setMeshDimension(meshDim);
75 * Returns a new MEDCouplingUMesh which is a full copy of \a this one. No data is shared
76 * between \a this and the new mesh.
77 * \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
78 * delete this mesh using decrRef() as it is no more needed.
80 MEDCouplingUMesh *MEDCouplingUMesh::deepCopy() const
87 * Returns a new MEDCouplingUMesh which is a copy of \a this one.
88 * \param [in] recDeepCpy - if \a true, the copy is deep, else all data arrays of \a
89 * this mesh are shared by the new mesh.
90 * \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
91 * delete this mesh using decrRef() as it is no more needed.
93 MEDCouplingUMesh *MEDCouplingUMesh::clone(bool recDeepCpy) const
95 return new MEDCouplingUMesh(*this,recDeepCpy);
99 * This method behaves mostly like MEDCouplingUMesh::deepCopy method, except that only nodal connectivity arrays are deeply copied.
100 * The coordinates are shared between \a this and the returned instance.
102 * \return MEDCouplingUMesh * - A new object instance holding the copy of \a this (deep for connectivity, shallow for coordiantes)
103 * \sa MEDCouplingUMesh::deepCopy
105 MEDCouplingUMesh *MEDCouplingUMesh::deepCopyConnectivityOnly() const
107 checkConnectivityFullyDefined();
108 MCAuto<MEDCouplingUMesh> ret=clone(false);
109 MCAuto<DataArrayInt> c(getNodalConnectivity()->deepCopy()),ci(getNodalConnectivityIndex()->deepCopy());
110 ret->setConnectivity(c,ci);
114 void MEDCouplingUMesh::shallowCopyConnectivityFrom(const MEDCouplingPointSet *other)
117 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is null !");
118 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
120 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is not an MEDCouplingUMesh instance !");
121 MEDCouplingUMesh *otherC2=const_cast<MEDCouplingUMesh *>(otherC);//sorry :(
122 setConnectivity(otherC2->getNodalConnectivity(),otherC2->getNodalConnectivityIndex(),true);
125 std::size_t MEDCouplingUMesh::getHeapMemorySizeWithoutChildren() const
127 std::size_t ret(MEDCouplingPointSet::getHeapMemorySizeWithoutChildren());
131 std::vector<const BigMemoryObject *> MEDCouplingUMesh::getDirectChildrenWithNull() const
133 std::vector<const BigMemoryObject *> ret(MEDCouplingPointSet::getDirectChildrenWithNull());
134 ret.push_back(_nodal_connec);
135 ret.push_back(_nodal_connec_index);
139 void MEDCouplingUMesh::updateTime() const
141 MEDCouplingPointSet::updateTime();
144 updateTimeWith(*_nodal_connec);
146 if(_nodal_connec_index)
148 updateTimeWith(*_nodal_connec_index);
152 MEDCouplingUMesh::MEDCouplingUMesh():_mesh_dim(-2),_nodal_connec(0),_nodal_connec_index(0)
157 * Checks if \a this mesh is well defined. If no exception is thrown by this method,
158 * then \a this mesh is most probably is writable, exchangeable and available for most
159 * of algorithms. When a mesh is constructed from scratch, it is a good habit to call
160 * this method to check that all is in order with \a this mesh.
161 * \throw If the mesh dimension is not set.
162 * \throw If the coordinates array is not set (if mesh dimension != -1 ).
163 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
164 * \throw If the connectivity data array has more than one component.
165 * \throw If the connectivity data array has a named component.
166 * \throw If the connectivity index data array has more than one component.
167 * \throw If the connectivity index data array has a named component.
169 void MEDCouplingUMesh::checkConsistencyLight() const
172 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
174 MEDCouplingPointSet::checkConsistencyLight();
175 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
177 if((int)INTERP_KERNEL::CellModel::GetCellModel(*iter).getDimension()!=_mesh_dim)
179 std::ostringstream message;
180 message << "Mesh invalid because dimension is " << _mesh_dim << " and there is presence of cell(s) with type " << (*iter);
181 throw INTERP_KERNEL::Exception(message.str().c_str());
186 if(_nodal_connec->getNumberOfComponents()!=1)
187 throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to be with number of components set to one !");
188 if(_nodal_connec->getInfoOnComponent(0)!="")
189 throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to have no info on its single component !");
193 throw INTERP_KERNEL::Exception("Nodal connectivity array is not defined !");
194 if(_nodal_connec_index)
196 if(_nodal_connec_index->getNumberOfComponents()!=1)
197 throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to be with number of components set to one !");
198 if(_nodal_connec_index->getInfoOnComponent(0)!="")
199 throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to have no info on its single component !");
203 throw INTERP_KERNEL::Exception("Nodal connectivity index array is not defined !");
207 * Checks if \a this mesh is well defined. If no exception is thrown by this method,
208 * then \a this mesh is most probably is writable, exchangeable and available for all
209 * algorithms. <br> In addition to the checks performed by checkConsistencyLight(), this
210 * method thoroughly checks the nodal connectivity.
211 * \param [in] eps - a not used parameter.
212 * \throw If the mesh dimension is not set.
213 * \throw If the coordinates array is not set (if mesh dimension != -1 ).
214 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
215 * \throw If the connectivity data array has more than one component.
216 * \throw If the connectivity data array has a named component.
217 * \throw If the connectivity index data array has more than one component.
218 * \throw If the connectivity index data array has a named component.
219 * \throw If number of nodes defining an element does not correspond to the type of element.
220 * \throw If the nodal connectivity includes an invalid node id.
222 void MEDCouplingUMesh::checkConsistency(double eps) const
224 checkConsistencyLight();
227 int meshDim=getMeshDimension();
228 int nbOfNodes=getNumberOfNodes();
229 int nbOfCells=getNumberOfCells();
230 const int *ptr=_nodal_connec->getConstPointer();
231 const int *ptrI=_nodal_connec_index->getConstPointer();
232 for(int i=0;i<nbOfCells;i++)
234 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)ptr[ptrI[i]]);
235 if((int)cm.getDimension()!=meshDim)
237 std::ostringstream oss;
238 oss << "MEDCouplingUMesh::checkConsistency : cell << #" << i<< " with type Type " << cm.getRepr() << " in 'this' whereas meshdim == " << meshDim << " !";
239 throw INTERP_KERNEL::Exception(oss.str());
241 int nbOfNodesInCell=ptrI[i+1]-ptrI[i]-1;
243 if(nbOfNodesInCell!=(int)cm.getNumberOfNodes())
245 std::ostringstream oss;
246 oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with static Type '" << cm.getRepr() << "' has " << cm.getNumberOfNodes();
247 oss << " nodes whereas in connectivity there is " << nbOfNodesInCell << " nodes ! Looks very bad !";
248 throw INTERP_KERNEL::Exception(oss.str());
250 if(cm.isQuadratic() && cm.isDynamic() && meshDim == 2)
251 if (nbOfNodesInCell % 2 || nbOfNodesInCell < 4)
253 std::ostringstream oss;
254 oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with quadratic type '" << cm.getRepr() << "' has " << nbOfNodesInCell;
255 oss << " nodes. This should be even, and greater or equal than 4!! Looks very bad!";
256 throw INTERP_KERNEL::Exception(oss.str());
258 for(const int *w=ptr+ptrI[i]+1;w!=ptr+ptrI[i+1];w++)
263 if(nodeId>=nbOfNodes)
265 std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " whereas there are only " << nbOfNodes << " nodes in the mesh !";
266 throw INTERP_KERNEL::Exception(oss.str());
271 std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " in connectivity ! sounds bad !";
272 throw INTERP_KERNEL::Exception(oss.str());
276 if((INTERP_KERNEL::NormalizedCellType)(ptr[ptrI[i]])!=INTERP_KERNEL::NORM_POLYHED)
278 std::ostringstream oss; oss << "Cell #" << i << " is built with node #-1 in connectivity ! sounds bad !";
279 throw INTERP_KERNEL::Exception(oss.str());
287 * Sets dimension of \a this mesh. The mesh dimension in general depends on types of
288 * elements contained in the mesh. For more info on the mesh dimension see
289 * \ref MEDCouplingUMeshPage.
290 * \param [in] meshDim - a new mesh dimension.
291 * \throw If \a meshDim is invalid. A valid range is <em> -1 <= meshDim <= 3</em>.
293 void MEDCouplingUMesh::setMeshDimension(int meshDim)
295 if(meshDim<-1 || meshDim>3)
296 throw INTERP_KERNEL::Exception("Invalid meshDim specified ! Must be greater or equal to -1 and lower or equal to 3 !");
302 * Allocates memory to store an estimation of the given number of cells. The closer is the estimation to the number of cells effectively inserted,
303 * 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.
304 * If a nodal connectivity previouly existed before the call of this method, it will be reset.
306 * \param [in] nbOfCells - estimation of the number of cell \a this mesh will contain.
308 * \if ENABLE_EXAMPLES
309 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
310 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
313 void MEDCouplingUMesh::allocateCells(int nbOfCells)
316 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::allocateCells : the input number of cells should be >= 0 !");
317 if(_nodal_connec_index)
319 _nodal_connec_index->decrRef();
323 _nodal_connec->decrRef();
325 _nodal_connec_index=DataArrayInt::New();
326 _nodal_connec_index->reserve(nbOfCells+1);
327 _nodal_connec_index->pushBackSilent(0);
328 _nodal_connec=DataArrayInt::New();
329 _nodal_connec->reserve(2*nbOfCells);
335 * Appends a cell to the connectivity array. For deeper understanding what is
336 * happening see \ref MEDCouplingUMeshNodalConnectivity.
337 * \param [in] type - type of cell to add.
338 * \param [in] size - number of nodes constituting this cell.
339 * \param [in] nodalConnOfCell - the connectivity of the cell to add.
341 * \if ENABLE_EXAMPLES
342 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
343 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
346 void MEDCouplingUMesh::insertNextCell(INTERP_KERNEL::NormalizedCellType type, int size, const int *nodalConnOfCell)
348 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
349 if(_nodal_connec_index==0)
350 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::insertNextCell : nodal connectivity not set ! invoke allocateCells before calling insertNextCell !");
351 if((int)cm.getDimension()==_mesh_dim)
354 if(size!=(int)cm.getNumberOfNodes())
356 std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : Trying to push a " << cm.getRepr() << " cell with a size of " << size;
357 oss << " ! Expecting " << cm.getNumberOfNodes() << " !";
358 throw INTERP_KERNEL::Exception(oss.str());
360 int idx=_nodal_connec_index->back();
362 _nodal_connec_index->pushBackSilent(val);
363 _nodal_connec->writeOnPlace(idx,type,nodalConnOfCell,size);
368 std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : cell type " << cm.getRepr() << " has a dimension " << cm.getDimension();
369 oss << " whereas Mesh Dimension of current UMesh instance is set to " << _mesh_dim << " ! Please invoke \"setMeshDimension\" method before or invoke ";
370 oss << "\"MEDCouplingUMesh::New\" static method with 2 parameters name and meshDimension !";
371 throw INTERP_KERNEL::Exception(oss.str());
376 * Compacts data arrays to release unused memory. This method is to be called after
377 * finishing cell insertion using \a this->insertNextCell().
379 * \if ENABLE_EXAMPLES
380 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
381 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
384 void MEDCouplingUMesh::finishInsertingCells()
386 _nodal_connec->pack();
387 _nodal_connec_index->pack();
388 _nodal_connec->declareAsNew();
389 _nodal_connec_index->declareAsNew();
394 * Entry point for iteration over cells of this. Warning the returned cell iterator should be deallocated.
395 * Useful for python users.
397 MEDCouplingUMeshCellIterator *MEDCouplingUMesh::cellIterator()
399 return new MEDCouplingUMeshCellIterator(this);
403 * Entry point for iteration over cells groups geo types per geotypes. Warning the returned cell iterator should be deallocated.
404 * If \a this is not so that that cells are grouped by geo types this method will throw an exception.
405 * In this case MEDCouplingUMesh::sortCellsInMEDFileFrmt or MEDCouplingUMesh::rearrange2ConsecutiveCellTypes methods for example can be called before invoking this method.
406 * Useful for python users.
408 MEDCouplingUMeshCellByTypeEntry *MEDCouplingUMesh::cellsByType()
410 if(!checkConsecutiveCellTypes())
411 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::cellsByType : this mesh is not sorted by type !");
412 return new MEDCouplingUMeshCellByTypeEntry(this);
416 * Returns a set of all cell types available in \a this mesh.
417 * \return std::set<INTERP_KERNEL::NormalizedCellType> - the set of cell types.
418 * \warning this method does not throw any exception even if \a this is not defined.
419 * \sa MEDCouplingUMesh::getAllGeoTypesSorted
421 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypes() const
427 * This method returns the sorted list of geometric types in \a this.
428 * 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
429 * having the same geometric type. So a same geometric type can appear more than once if the cells are not sorted per geometric type.
431 * \throw if connectivity in \a this is not correctly defined.
433 * \sa MEDCouplingMesh::getAllGeoTypes
435 std::vector<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypesSorted() const
437 std::vector<INTERP_KERNEL::NormalizedCellType> ret;
438 checkConnectivityFullyDefined();
439 int nbOfCells(getNumberOfCells());
442 if(getNodalConnectivityArrayLen()<1)
443 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAllGeoTypesSorted : the connectivity in this seems invalid !");
444 const int *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin());
445 ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci++]);
446 for(int i=1;i<nbOfCells;i++,ci++)
447 if(ret.back()!=((INTERP_KERNEL::NormalizedCellType)c[*ci]))
448 ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci]);
453 * This method is a method that compares \a this and \a other.
454 * This method compares \b all attributes, even names and component names.
456 bool MEDCouplingUMesh::isEqualIfNotWhy(const MEDCouplingMesh *other, double prec, std::string& reason) const
459 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isEqualIfNotWhy : input other pointer is null !");
460 std::ostringstream oss; oss.precision(15);
461 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
464 reason="mesh given in input is not castable in MEDCouplingUMesh !";
467 if(!MEDCouplingPointSet::isEqualIfNotWhy(other,prec,reason))
469 if(_mesh_dim!=otherC->_mesh_dim)
471 oss << "umesh dimension mismatch : this mesh dimension=" << _mesh_dim << " other mesh dimension=" << otherC->_mesh_dim;
475 if(_types!=otherC->_types)
477 oss << "umesh geometric type mismatch :\nThis geometric types are :";
478 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
479 { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
480 oss << "\nOther geometric types are :";
481 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=otherC->_types.begin();iter!=otherC->_types.end();iter++)
482 { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
486 if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
487 if(_nodal_connec==0 || otherC->_nodal_connec==0)
489 reason="Only one UMesh between the two this and other has its nodal connectivity DataArrayInt defined !";
492 if(_nodal_connec!=otherC->_nodal_connec)
493 if(!_nodal_connec->isEqualIfNotWhy(*otherC->_nodal_connec,reason))
495 reason.insert(0,"Nodal connectivity DataArrayInt differ : ");
498 if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
499 if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
501 reason="Only one UMesh between the two this and other has its nodal connectivity index DataArrayInt defined !";
504 if(_nodal_connec_index!=otherC->_nodal_connec_index)
505 if(!_nodal_connec_index->isEqualIfNotWhy(*otherC->_nodal_connec_index,reason))
507 reason.insert(0,"Nodal connectivity index DataArrayInt differ : ");
514 * Checks if data arrays of this mesh (node coordinates, nodal
515 * connectivity of cells, etc) of two meshes are same. Textual data like name etc. are
517 * \param [in] other - the mesh to compare with.
518 * \param [in] prec - precision value used to compare node coordinates.
519 * \return bool - \a true if the two meshes are same.
521 bool MEDCouplingUMesh::isEqualWithoutConsideringStr(const MEDCouplingMesh *other, double prec) const
523 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
526 if(!MEDCouplingPointSet::isEqualWithoutConsideringStr(other,prec))
528 if(_mesh_dim!=otherC->_mesh_dim)
530 if(_types!=otherC->_types)
532 if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
533 if(_nodal_connec==0 || otherC->_nodal_connec==0)
535 if(_nodal_connec!=otherC->_nodal_connec)
536 if(!_nodal_connec->isEqualWithoutConsideringStr(*otherC->_nodal_connec))
538 if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
539 if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
541 if(_nodal_connec_index!=otherC->_nodal_connec_index)
542 if(!_nodal_connec_index->isEqualWithoutConsideringStr(*otherC->_nodal_connec_index))
548 * Checks if \a this and \a other meshes are geometrically equivalent with high
549 * probability, else an exception is thrown. The meshes are considered equivalent if
550 * (1) meshes contain the same number of nodes and the same number of elements of the
551 * same types (2) three cells of the two meshes (first, last and middle) are based
552 * on coincident nodes (with a specified precision).
553 * \param [in] other - the mesh to compare with.
554 * \param [in] prec - the precision used to compare nodes of the two meshes.
555 * \throw If the two meshes do not match.
557 void MEDCouplingUMesh::checkFastEquivalWith(const MEDCouplingMesh *other, double prec) const
559 MEDCouplingPointSet::checkFastEquivalWith(other,prec);
560 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
562 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkFastEquivalWith : Two meshes are not not unstructured !");
566 * Returns the reverse nodal connectivity. The reverse nodal connectivity enumerates
567 * cells each node belongs to.
568 * \warning For speed reasons, this method does not check if node ids in the nodal
569 * connectivity correspond to the size of node coordinates array.
570 * \param [in,out] revNodal - an array holding ids of cells sharing each node.
571 * \param [in,out] revNodalIndx - an array, of length \a this->getNumberOfNodes() + 1,
572 * dividing cell ids in \a revNodal into groups each referring to one
573 * node. Its every element (except the last one) is an index pointing to the
574 * first id of a group of cells. For example cells sharing the node #1 are
575 * described by following range of indices:
576 * [ \a revNodalIndx[1], \a revNodalIndx[2] ) and the cell ids are
577 * \a revNodal[ \a revNodalIndx[1] ], \a revNodal[ \a revNodalIndx[1] + 1], ...
578 * Number of cells sharing the *i*-th node is
579 * \a revNodalIndx[ *i*+1 ] - \a revNodalIndx[ *i* ].
580 * \throw If the coordinates array is not set.
581 * \throw If the nodal connectivity of cells is not defined.
583 * \if ENABLE_EXAMPLES
584 * \ref cpp_mcumesh_getReverseNodalConnectivity "Here is a C++ example".<br>
585 * \ref py_mcumesh_getReverseNodalConnectivity "Here is a Python example".
588 void MEDCouplingUMesh::getReverseNodalConnectivity(DataArrayInt *revNodal, DataArrayInt *revNodalIndx) const
591 int nbOfNodes=getNumberOfNodes();
592 int *revNodalIndxPtr=(int *)malloc((nbOfNodes+1)*sizeof(int));
593 revNodalIndx->useArray(revNodalIndxPtr,true,C_DEALLOC,nbOfNodes+1,1);
594 std::fill(revNodalIndxPtr,revNodalIndxPtr+nbOfNodes+1,0);
595 const int *conn=_nodal_connec->getConstPointer();
596 const int *connIndex=_nodal_connec_index->getConstPointer();
597 int nbOfCells=getNumberOfCells();
598 int nbOfEltsInRevNodal=0;
599 for(int eltId=0;eltId<nbOfCells;eltId++)
601 const int *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
602 const int *endNdlConnOfCurCell=conn+connIndex[eltId+1];
603 for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
604 if(*iter>=0)//for polyhedrons
606 nbOfEltsInRevNodal++;
607 revNodalIndxPtr[(*iter)+1]++;
610 std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<int>());
611 int *revNodalPtr=(int *)malloc((nbOfEltsInRevNodal)*sizeof(int));
612 revNodal->useArray(revNodalPtr,true,C_DEALLOC,nbOfEltsInRevNodal,1);
613 std::fill(revNodalPtr,revNodalPtr+nbOfEltsInRevNodal,-1);
614 for(int eltId=0;eltId<nbOfCells;eltId++)
616 const int *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
617 const int *endNdlConnOfCurCell=conn+connIndex[eltId+1];
618 for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
619 if(*iter>=0)//for polyhedrons
620 *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind2nd(std::equal_to<int>(),-1))=eltId;
626 int MEDCouplingFastNbrer(int id, unsigned nb, const INTERP_KERNEL::CellModel& cm, bool compute, const int *conn1, const int *conn2)
631 int MEDCouplingOrientationSensitiveNbrer(int id, unsigned nb, const INTERP_KERNEL::CellModel& cm, bool compute, const int *conn1, const int *conn2)
637 if(cm.getOrientationStatus(nb,conn1,conn2))
644 class MinusOneSonsGenerator
647 MinusOneSonsGenerator(const INTERP_KERNEL::CellModel& cm):_cm(cm) { }
648 unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfSons2(conn,lgth); }
649 unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillSonCellNodalConnectivity2(sonId,nodalConn,lgth,sonNodalConn,typeOfSon); }
650 static const int DELTA=1;
652 const INTERP_KERNEL::CellModel& _cm;
655 class MinusOneSonsGeneratorBiQuadratic
658 MinusOneSonsGeneratorBiQuadratic(const INTERP_KERNEL::CellModel& cm):_cm(cm) { }
659 unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfSons2(conn,lgth); }
660 unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillSonCellNodalConnectivity4(sonId,nodalConn,lgth,sonNodalConn,typeOfSon); }
661 static const int DELTA=1;
663 const INTERP_KERNEL::CellModel& _cm;
666 class MinusTwoSonsGenerator
669 MinusTwoSonsGenerator(const INTERP_KERNEL::CellModel& cm):_cm(cm) { }
670 unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfEdgesIn3D(conn,lgth); }
671 unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillSonEdgesNodalConnectivity3D(sonId,nodalConn,lgth,sonNodalConn,typeOfSon); }
672 static const int DELTA=2;
674 const INTERP_KERNEL::CellModel& _cm;
677 class MicroEdgesGenerator2D
680 MicroEdgesGenerator2D(const INTERP_KERNEL::CellModel& cm):_cm(cm) { }
681 unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfMicroEdges(); }
682 unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillMicroEdgeNodalConnectivity(sonId,nodalConn,sonNodalConn,typeOfSon); }
683 static const int DELTA=1;
685 const INTERP_KERNEL::CellModel& _cm;
688 class MicroEdgesGenerator3D
691 MicroEdgesGenerator3D(const INTERP_KERNEL::CellModel& cm):_cm(cm) { }
692 unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfMicroEdges(); }
693 unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillMicroEdgeNodalConnectivity(sonId,nodalConn,sonNodalConn,typeOfSon); }
694 static const int DELTA=2;
696 const INTERP_KERNEL::CellModel& _cm;
702 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
703 * this->getMeshDimension(), that bound cells of \a this mesh. In addition arrays
704 * describing correspondence between cells of \a this and the result meshes are
705 * returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending connectivity,
706 * i.e. enumerate cells of the result mesh bounding each cell of \a this mesh. The
707 * arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
708 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
709 * \warning For speed reasons, this method does not check if node ids in the nodal
710 * connectivity correspond to the size of node coordinates array.
711 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
712 * to write this mesh to the MED file, its cells must be sorted using
713 * sortCellsInMEDFileFrmt().
714 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
715 * each cell of \a this mesh.
716 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
717 * dividing cell ids in \a desc into groups each referring to one
718 * cell of \a this mesh. Its every element (except the last one) is an index
719 * pointing to the first id of a group of cells. For example cells of the
720 * result mesh bounding the cell #1 of \a this mesh are described by following
722 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
723 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
724 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
725 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
726 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
727 * by each cell of the result mesh.
728 * \param [in,out] revDescIndx - the array, of length one more than number of cells
729 * in the result mesh,
730 * dividing cell ids in \a revDesc into groups each referring to one
731 * cell of the result mesh the same way as \a descIndx divides \a desc.
732 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
733 * delete this mesh using decrRef() as it is no more needed.
734 * \throw If the coordinates array is not set.
735 * \throw If the nodal connectivity of cells is node defined.
736 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
737 * revDescIndx == NULL.
739 * \if ENABLE_EXAMPLES
740 * \ref cpp_mcumesh_buildDescendingConnectivity "Here is a C++ example".<br>
741 * \ref py_mcumesh_buildDescendingConnectivity "Here is a Python example".
743 * \sa buildDescendingConnectivity2()
745 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
747 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
751 * \a this has to have a mesh dimension equal to 3. If it is not the case an INTERP_KERNEL::Exception will be thrown.
752 * This behaves exactly as MEDCouplingUMesh::buildDescendingConnectivity does except that this method compute directly the transition from mesh dimension 3 to sub edges (dimension 1)
753 * in one shot. That is to say that this method is equivalent to 2 successive calls to MEDCouplingUMesh::buildDescendingConnectivity.
754 * This method returns 4 arrays and a mesh as MEDCouplingUMesh::buildDescendingConnectivity does.
755 * \sa MEDCouplingUMesh::buildDescendingConnectivity
757 MEDCouplingUMesh *MEDCouplingUMesh::explode3DMeshTo1D(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
760 if(getMeshDimension()!=3)
761 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explode3DMeshTo1D : This has to have a mesh dimension to 3 !");
762 return buildDescendingConnectivityGen<MinusTwoSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
766 * This method computes the micro edges constituting each cell in \a this. Micro edge is an edge for non quadratic cells. Micro edge is an half edge for quadratic cells.
767 * This method works for both meshes with mesh dimenstion equal to 2 or 3. Dynamical cells are not supported (polygons, polyhedrons...)
769 * \sa explode3DMeshTo1D, buildDescendingConnectiviy
771 MEDCouplingUMesh *MEDCouplingUMesh::explodeMeshIntoMicroEdges(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
774 switch(getMeshDimension())
777 return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
779 return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
781 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explodeMeshIntoMicroEdges : Only 2D and 3D supported !");
786 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
787 * this->getMeshDimension(), that bound cells of \a this mesh. In
788 * addition arrays describing correspondence between cells of \a this and the result
789 * meshes are returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending
790 * connectivity, i.e. enumerate cells of the result mesh bounding each cell of \a this
791 * mesh. This method differs from buildDescendingConnectivity() in that apart
792 * from cell ids, \a desc returns mutual orientation of cells in \a this and the
793 * result meshes. So a positive id means that order of nodes in corresponding cells
794 * of two meshes is same, and a negative id means a reverse order of nodes. Since a
795 * cell with id #0 can't be negative, the array \a desc returns ids in FORTRAN mode,
796 * i.e. cell ids are one-based.
797 * Arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
798 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
799 * \warning For speed reasons, this method does not check if node ids in the nodal
800 * connectivity correspond to the size of node coordinates array.
801 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
802 * to write this mesh to the MED file, its cells must be sorted using
803 * sortCellsInMEDFileFrmt().
804 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
805 * each cell of \a this mesh.
806 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
807 * dividing cell ids in \a desc into groups each referring to one
808 * cell of \a this mesh. Its every element (except the last one) is an index
809 * pointing to the first id of a group of cells. For example cells of the
810 * result mesh bounding the cell #1 of \a this mesh are described by following
812 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
813 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
814 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
815 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
816 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
817 * by each cell of the result mesh.
818 * \param [in,out] revDescIndx - the array, of length one more than number of cells
819 * in the result mesh,
820 * dividing cell ids in \a revDesc into groups each referring to one
821 * cell of the result mesh the same way as \a descIndx divides \a desc.
822 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This result mesh
823 * shares the node coordinates array with \a this mesh. The caller is to
824 * delete this mesh using decrRef() as it is no more needed.
825 * \throw If the coordinates array is not set.
826 * \throw If the nodal connectivity of cells is node defined.
827 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
828 * revDescIndx == NULL.
830 * \if ENABLE_EXAMPLES
831 * \ref cpp_mcumesh_buildDescendingConnectivity2 "Here is a C++ example".<br>
832 * \ref py_mcumesh_buildDescendingConnectivity2 "Here is a Python example".
834 * \sa buildDescendingConnectivity()
836 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
838 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingOrientationSensitiveNbrer);
842 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
843 * For speed reasons no check of this will be done. This method calls
844 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
845 * This method lists cell by cell in \b this which are its neighbors. To compute the result
846 * only connectivities are considered.
847 * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
848 * The format of return is hence \ref numbering-indirect.
850 * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly
851 * allocated and should be dealt by the caller. \b neighborsIndx 2nd output
852 * parameter allows to select the right part in this array (\ref numbering-indirect). The number of tuples
853 * is equal to the last values in \b neighborsIndx.
854 * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be
855 * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
857 void MEDCouplingUMesh::computeNeighborsOfCells(DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx) const
859 MCAuto<DataArrayInt> desc=DataArrayInt::New();
860 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
861 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
862 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
863 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
865 ComputeNeighborsOfCellsAdv(desc,descIndx,revDesc,revDescIndx,neighbors,neighborsIndx);
868 void MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne(const DataArrayInt *nodeNeigh, const DataArrayInt *nodeNeighI, MCAuto<DataArrayInt>& cellNeigh, MCAuto<DataArrayInt>& cellNeighIndex) const
870 if(!nodeNeigh || !nodeNeighI)
871 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : null pointer !");
872 checkConsistencyLight();
873 nodeNeigh->checkAllocated(); nodeNeighI->checkAllocated();
874 nodeNeigh->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh");
875 nodeNeighI->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh index");
876 nodeNeighI->checkNbOfTuples(1+getNumberOfNodes(),"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : invalid length");
877 int nbCells(getNumberOfCells());
878 const int *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin()),*ne(nodeNeigh->begin()),*nei(nodeNeighI->begin());
879 cellNeigh=DataArrayInt::New(); cellNeigh->alloc(0,1); cellNeighIndex=DataArrayInt::New(); cellNeighIndex->alloc(1,1); cellNeighIndex->setIJ(0,0,0);
880 for(int i=0;i<nbCells;i++)
883 for(const int *it=c+ci[i]+1;it!=c+ci[i+1];it++)
885 s.insert(ne+nei[*it],ne+nei[*it+1]);
887 cellNeigh->insertAtTheEnd(s.begin(),s.end());
888 cellNeighIndex->pushBackSilent(cellNeigh->getNumberOfTuples());
893 * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm
894 * of MEDCouplingUMesh::computeNeighborsOfCells.
895 * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is
896 * typically the case to extract a set a neighbours,
897 * excluding a set of meshdim-1 cells in input descending connectivity.
898 * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx (\ref numbering-indirect) input params are
899 * the result of MEDCouplingUMesh::buildDescendingConnectivity.
900 * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities
902 * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
904 * \param [in] desc descending connectivity array.
905 * \param [in] descIndx descending connectivity index array used to walk through \b desc (\ref numbering-indirect).
906 * \param [in] revDesc reverse descending connectivity array.
907 * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc (\ref numbering-indirect).
908 * \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
909 * parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
910 * \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.
912 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayInt *desc, const DataArrayInt *descIndx, const DataArrayInt *revDesc, const DataArrayInt *revDescIndx,
913 DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx)
915 if(!desc || !descIndx || !revDesc || !revDescIndx)
916 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
917 const int *descPtr=desc->getConstPointer();
918 const int *descIPtr=descIndx->getConstPointer();
919 const int *revDescPtr=revDesc->getConstPointer();
920 const int *revDescIPtr=revDescIndx->getConstPointer();
922 int nbCells=descIndx->getNumberOfTuples()-1;
923 MCAuto<DataArrayInt> out0=DataArrayInt::New();
924 MCAuto<DataArrayInt> out1=DataArrayInt::New(); out1->alloc(nbCells+1,1);
925 int *out1Ptr=out1->getPointer();
927 out0->reserve(desc->getNumberOfTuples());
928 for(int i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
930 for(const int *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
932 std::set<int> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
934 out0->insertAtTheEnd(s.begin(),s.end());
936 *out1Ptr=out0->getNumberOfTuples();
938 neighbors=out0.retn();
939 neighborsIndx=out1.retn();
943 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
944 * For speed reasons no check of this will be done. This method calls
945 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
946 * This method lists node by node in \b this which are its neighbors. To compute the result
947 * only connectivities are considered.
948 * The neighbor nodes of node having id 'nodeId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
950 * \param [out] neighbors is an array storing all the neighbors of all nodes in \b this. This array
951 * is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
952 * parameter allows to select the right part in this array (\ref numbering-indirect).
953 * The number of tuples is equal to the last values in \b neighborsIndx.
954 * \param [out] neighborsIdx is an array of size this->getNumberOfCells()+1 newly allocated and should
955 * be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
957 void MEDCouplingUMesh::computeNeighborsOfNodes(DataArrayInt *&neighbors, DataArrayInt *&neighborsIdx) const
960 int mdim(getMeshDimension()),nbNodes(getNumberOfNodes());
961 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descIndx(DataArrayInt::New()),revDesc(DataArrayInt::New()),revDescIndx(DataArrayInt::New());
962 MCAuto<MEDCouplingUMesh> mesh1D;
967 mesh1D=explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx);
972 mesh1D=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
977 mesh1D=const_cast<MEDCouplingUMesh *>(this);
983 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2,1] !");
986 desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=0; revDescIndx=0;
987 mesh1D->getReverseNodalConnectivity(desc,descIndx);
988 MCAuto<DataArrayInt> ret0(DataArrayInt::New());
989 ret0->alloc(desc->getNumberOfTuples(),1);
990 int *r0Pt(ret0->getPointer());
991 const int *c1DPtr(mesh1D->getNodalConnectivity()->begin()),*rn(desc->begin()),*rni(descIndx->begin());
992 for(int i=0;i<nbNodes;i++,rni++)
994 for(const int *oneDCellIt=rn+rni[0];oneDCellIt!=rn+rni[1];oneDCellIt++)
995 *r0Pt++=c1DPtr[3*(*oneDCellIt)+1]==i?c1DPtr[3*(*oneDCellIt)+2]:c1DPtr[3*(*oneDCellIt)+1];
997 neighbors=ret0.retn();
998 neighborsIdx=descIndx.retn();
1004 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
1005 * For speed reasons no check of this will be done.
1007 template<class SonsGenerator>
1008 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivityGen(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx, DimM1DescNbrer nbrer) const
1010 if(!desc || !descIndx || !revDesc || !revDescIndx)
1011 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildDescendingConnectivityGen : present of a null pointer in input !");
1012 checkConnectivityFullyDefined();
1013 int nbOfCells=getNumberOfCells();
1014 int nbOfNodes=getNumberOfNodes();
1015 MCAuto<DataArrayInt> revNodalIndx=DataArrayInt::New(); revNodalIndx->alloc(nbOfNodes+1,1); revNodalIndx->fillWithZero();
1016 int *revNodalIndxPtr=revNodalIndx->getPointer();
1017 const int *conn=_nodal_connec->getConstPointer();
1018 const int *connIndex=_nodal_connec_index->getConstPointer();
1019 std::string name="Mesh constituent of "; name+=getName();
1020 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(name,getMeshDimension()-SonsGenerator::DELTA);
1021 ret->setCoords(getCoords());
1022 ret->allocateCells(2*nbOfCells);
1023 descIndx->alloc(nbOfCells+1,1);
1024 MCAuto<DataArrayInt> revDesc2(DataArrayInt::New()); revDesc2->reserve(2*nbOfCells);
1025 int *descIndxPtr=descIndx->getPointer(); *descIndxPtr++=0;
1026 for(int eltId=0;eltId<nbOfCells;eltId++,descIndxPtr++)
1028 int pos=connIndex[eltId];
1029 int posP1=connIndex[eltId+1];
1030 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[pos]);
1031 SonsGenerator sg(cm);
1032 unsigned nbOfSons=sg.getNumberOfSons2(conn+pos+1,posP1-pos-1);
1033 INTERP_KERNEL::AutoPtr<int> tmp=new int[posP1-pos];
1034 for(unsigned i=0;i<nbOfSons;i++)
1036 INTERP_KERNEL::NormalizedCellType cmsId;
1037 unsigned nbOfNodesSon=sg.fillSonCellNodalConnectivity2(i,conn+pos+1,posP1-pos-1,tmp,cmsId);
1038 for(unsigned k=0;k<nbOfNodesSon;k++)
1040 revNodalIndxPtr[tmp[k]+1]++;
1041 ret->insertNextCell(cmsId,nbOfNodesSon,tmp);
1042 revDesc2->pushBackSilent(eltId);
1044 descIndxPtr[0]=descIndxPtr[-1]+(int)nbOfSons;
1046 int nbOfCellsM1=ret->getNumberOfCells();
1047 std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<int>());
1048 MCAuto<DataArrayInt> revNodal=DataArrayInt::New(); revNodal->alloc(revNodalIndx->back(),1);
1049 std::fill(revNodal->getPointer(),revNodal->getPointer()+revNodalIndx->back(),-1);
1050 int *revNodalPtr=revNodal->getPointer();
1051 const int *connM1=ret->getNodalConnectivity()->getConstPointer();
1052 const int *connIndexM1=ret->getNodalConnectivityIndex()->getConstPointer();
1053 for(int eltId=0;eltId<nbOfCellsM1;eltId++)
1055 const int *strtNdlConnOfCurCell=connM1+connIndexM1[eltId]+1;
1056 const int *endNdlConnOfCurCell=connM1+connIndexM1[eltId+1];
1057 for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
1058 if(*iter>=0)//for polyhedrons
1059 *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind2nd(std::equal_to<int>(),-1))=eltId;
1062 DataArrayInt *commonCells=0,*commonCellsI=0;
1063 FindCommonCellsAlg(3,0,ret->getNodalConnectivity(),ret->getNodalConnectivityIndex(),revNodal,revNodalIndx,commonCells,commonCellsI);
1064 MCAuto<DataArrayInt> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1065 const int *commonCellsPtr(commonCells->getConstPointer()),*commonCellsIPtr(commonCellsI->getConstPointer());
1066 int newNbOfCellsM1=-1;
1067 MCAuto<DataArrayInt> o2nM1=DataArrayInt::ConvertIndexArrayToO2N(nbOfCellsM1,commonCells->begin(),
1068 commonCellsI->begin(),commonCellsI->end(),newNbOfCellsM1);
1069 std::vector<bool> isImpacted(nbOfCellsM1,false);
1070 for(const int *work=commonCellsI->begin();work!=commonCellsI->end()-1;work++)
1071 for(int work2=work[0];work2!=work[1];work2++)
1072 isImpacted[commonCellsPtr[work2]]=true;
1073 const int *o2nM1Ptr=o2nM1->getConstPointer();
1074 MCAuto<DataArrayInt> n2oM1=o2nM1->invertArrayO2N2N2OBis(newNbOfCellsM1);
1075 const int *n2oM1Ptr=n2oM1->getConstPointer();
1076 MCAuto<MEDCouplingUMesh> ret2=static_cast<MEDCouplingUMesh *>(ret->buildPartOfMySelf(n2oM1->begin(),n2oM1->end(),true));
1077 ret2->copyTinyInfoFrom(this);
1078 desc->alloc(descIndx->back(),1);
1079 int *descPtr=desc->getPointer();
1080 const INTERP_KERNEL::CellModel& cmsDft=INTERP_KERNEL::CellModel::GetCellModel(INTERP_KERNEL::NORM_POINT1);
1081 for(int i=0;i<nbOfCellsM1;i++,descPtr++)
1084 *descPtr=nbrer(o2nM1Ptr[i],0,cmsDft,false,0,0);
1087 if(i!=n2oM1Ptr[o2nM1Ptr[i]])
1089 const INTERP_KERNEL::CellModel& cms=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connM1[connIndexM1[i]]);
1090 *descPtr=nbrer(o2nM1Ptr[i],connIndexM1[i+1]-connIndexM1[i]-1,cms,true,connM1+connIndexM1[n2oM1Ptr[o2nM1Ptr[i]]]+1,connM1+connIndexM1[i]+1);
1093 *descPtr=nbrer(o2nM1Ptr[i],0,cmsDft,false,0,0);
1096 revDesc->reserve(newNbOfCellsM1);
1097 revDescIndx->alloc(newNbOfCellsM1+1,1);
1098 int *revDescIndxPtr=revDescIndx->getPointer(); *revDescIndxPtr++=0;
1099 const int *revDesc2Ptr=revDesc2->getConstPointer();
1100 for(int i=0;i<newNbOfCellsM1;i++,revDescIndxPtr++)
1102 int oldCellIdM1=n2oM1Ptr[i];
1103 if(!isImpacted[oldCellIdM1])
1105 revDesc->pushBackSilent(revDesc2Ptr[oldCellIdM1]);
1106 revDescIndxPtr[0]=revDescIndxPtr[-1]+1;
1110 for(int j=commonCellsIPtr[0];j<commonCellsIPtr[1];j++)
1111 revDesc->pushBackSilent(revDesc2Ptr[commonCellsPtr[j]]);
1112 revDescIndxPtr[0]=revDescIndxPtr[-1]+commonCellsIPtr[1]-commonCellsIPtr[0];
1120 struct MEDCouplingAccVisit
1122 MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1123 int operator()(int val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1124 int _new_nb_of_nodes;
1130 * Converts specified cells to either polygons (if \a this is a 2D mesh) or
1131 * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an
1132 * array of cell ids. Pay attention that after conversion all algorithms work slower
1133 * with \a this mesh than before conversion. <br> If an exception is thrown during the
1134 * conversion due presence of invalid ids in the array of cells to convert, as a
1135 * result \a this mesh contains some already converted elements. In this case the 2D
1136 * mesh remains valid but 3D mesh becomes \b inconsistent!
1137 * \warning This method can significantly modify the order of geometric types in \a this,
1138 * hence, to write this mesh to the MED file, its cells must be sorted using
1139 * sortCellsInMEDFileFrmt().
1140 * \param [in] cellIdsToConvertBg - the array holding ids of cells to convert.
1141 * \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a
1142 * cellIdsToConvertBg.
1143 * \throw If the coordinates array is not set.
1144 * \throw If the nodal connectivity of cells is node defined.
1145 * \throw If dimension of \a this mesh is not either 2 or 3.
1147 * \if ENABLE_EXAMPLES
1148 * \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".<br>
1149 * \ref py_mcumesh_convertToPolyTypes "Here is a Python example".
1152 void MEDCouplingUMesh::convertToPolyTypes(const int *cellIdsToConvertBg, const int *cellIdsToConvertEnd)
1154 checkFullyDefined();
1155 int dim=getMeshDimension();
1157 throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
1158 int nbOfCells(getNumberOfCells());
1161 const int *connIndex=_nodal_connec_index->getConstPointer();
1162 int *conn=_nodal_connec->getPointer();
1163 for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1165 if(*iter>=0 && *iter<nbOfCells)
1167 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
1168 if(!cm.isQuadratic())
1169 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
1171 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
1175 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1176 oss << " in range [0," << nbOfCells << ") !";
1177 throw INTERP_KERNEL::Exception(oss.str());
1183 int *connIndex(_nodal_connec_index->getPointer());
1184 const int *connOld(_nodal_connec->getConstPointer());
1185 MCAuto<DataArrayInt> connNew(DataArrayInt::New()),connNewI(DataArrayInt::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0);
1186 std::vector<bool> toBeDone(nbOfCells,false);
1187 for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1189 if(*iter>=0 && *iter<nbOfCells)
1190 toBeDone[*iter]=true;
1193 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1194 oss << " in range [0," << nbOfCells << ") !";
1195 throw INTERP_KERNEL::Exception(oss.str());
1198 for(int cellId=0;cellId<nbOfCells;cellId++)
1200 int pos(connIndex[cellId]),posP1(connIndex[cellId+1]);
1201 int lgthOld(posP1-pos-1);
1202 if(toBeDone[cellId])
1204 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connOld[pos]);
1205 unsigned nbOfFaces(cm.getNumberOfSons2(connOld+pos+1,lgthOld));
1206 int *tmp(new int[nbOfFaces*lgthOld+1]);
1207 int *work=tmp; *work++=INTERP_KERNEL::NORM_POLYHED;
1208 for(unsigned j=0;j<nbOfFaces;j++)
1210 INTERP_KERNEL::NormalizedCellType type;
1211 unsigned offset=cm.fillSonCellNodalConnectivity2(j,connOld+pos+1,lgthOld,work,type);
1215 std::size_t newLgth(std::distance(tmp,work)-1);//-1 for last -1
1216 connNew->pushBackValsSilent(tmp,tmp+newLgth);
1217 connNewI->pushBackSilent(connNewI->back()+(int)newLgth);
1222 connNew->pushBackValsSilent(connOld+pos,connOld+posP1);
1223 connNewI->pushBackSilent(connNewI->back()+posP1-pos);
1226 setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind.
1232 * Converts all cells to either polygons (if \a this is a 2D mesh) or
1233 * polyhedrons (if \a this is a 3D mesh).
1234 * \warning As this method is purely for user-friendliness and no optimization is
1235 * done to avoid construction of a useless vector, this method can be costly
1237 * \throw If the coordinates array is not set.
1238 * \throw If the nodal connectivity of cells is node defined.
1239 * \throw If dimension of \a this mesh is not either 2 or 3.
1241 void MEDCouplingUMesh::convertAllToPoly()
1243 int nbOfCells=getNumberOfCells();
1244 std::vector<int> cellIds(nbOfCells);
1245 for(int i=0;i<nbOfCells;i++)
1247 convertToPolyTypes(&cellIds[0],&cellIds[0]+cellIds.size());
1251 * Fixes nodal connectivity of invalid cells of type NORM_POLYHED. This method
1252 * expects that all NORM_POLYHED cells have connectivity similar to that of prismatic
1253 * volumes like NORM_HEXA8, NORM_PENTA6 etc., i.e. the first half of nodes describes a
1254 * base facet of the volume and the second half of nodes describes an opposite facet
1255 * having the same number of nodes as the base one. This method converts such
1256 * connectivity to a valid polyhedral format where connectivity of each facet is
1257 * explicitly described and connectivity of facets are separated by -1. If \a this mesh
1258 * contains a NORM_POLYHED cell with a valid connectivity, or an invalid connectivity is
1259 * not as expected, an exception is thrown and the mesh remains unchanged. Care of
1260 * a correct orientation of the first facet of a polyhedron, else orientation of a
1261 * corrected cell is reverse.<br>
1262 * This method is useful to build an extruded unstructured mesh with polyhedrons as
1263 * it releases the user from boring description of polyhedra connectivity in the valid
1265 * \throw If \a this->getMeshDimension() != 3.
1266 * \throw If \a this->getSpaceDimension() != 3.
1267 * \throw If the nodal connectivity of cells is not defined.
1268 * \throw If the coordinates array is not set.
1269 * \throw If \a this mesh contains polyhedrons with the valid connectivity.
1270 * \throw If \a this mesh contains polyhedrons with odd number of nodes.
1272 * \if ENABLE_EXAMPLES
1273 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
1274 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
1277 void MEDCouplingUMesh::convertExtrudedPolyhedra()
1279 checkFullyDefined();
1280 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1281 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
1282 int nbOfCells=getNumberOfCells();
1283 MCAuto<DataArrayInt> newCi=DataArrayInt::New();
1284 newCi->alloc(nbOfCells+1,1);
1285 int *newci=newCi->getPointer();
1286 const int *ci=_nodal_connec_index->getConstPointer();
1287 const int *c=_nodal_connec->getConstPointer();
1289 for(int i=0;i<nbOfCells;i++)
1291 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1292 if(type==INTERP_KERNEL::NORM_POLYHED)
1294 if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
1296 std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
1297 throw INTERP_KERNEL::Exception(oss.str());
1299 std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
1302 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 !";
1303 throw INTERP_KERNEL::Exception(oss.str());
1306 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)
1309 newci[i+1]=(ci[i+1]-ci[i])+newci[i];
1311 MCAuto<DataArrayInt> newC=DataArrayInt::New();
1312 newC->alloc(newci[nbOfCells],1);
1313 int *newc=newC->getPointer();
1314 for(int i=0;i<nbOfCells;i++)
1316 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1317 if(type==INTERP_KERNEL::NORM_POLYHED)
1319 std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
1320 newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
1322 for(std::size_t j=0;j<n1;j++)
1324 newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
1326 newc[n1+5*j+1]=c[ci[i]+1+j];
1327 newc[n1+5*j+2]=c[ci[i]+1+j+n1];
1328 newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
1329 newc[n1+5*j+4]=c[ci[i]+1+(j+1)%n1];
1334 newc=std::copy(c+ci[i],c+ci[i+1],newc);
1336 _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
1337 _nodal_connec->decrRef(); _nodal_connec=newC.retn();
1342 * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D
1343 * mesh) to cells of classical types. This method is opposite to convertToPolyTypes().
1344 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
1345 * to write this mesh to the MED file, its cells must be sorted using
1346 * sortCellsInMEDFileFrmt().
1347 * \warning Cells (and most notably polyhedrons) must be correctly oriented for this to work
1348 * properly. See orientCorrectlyPolyhedrons() and arePolyhedronsNotCorrectlyOriented().
1349 * \return \c true if at least one cell has been converted, \c false else. In the
1350 * last case the nodal connectivity remains unchanged.
1351 * \throw If the coordinates array is not set.
1352 * \throw If the nodal connectivity of cells is not defined.
1353 * \throw If \a this->getMeshDimension() < 0.
1355 bool MEDCouplingUMesh::unPolyze()
1357 checkFullyDefined();
1358 int mdim=getMeshDimension();
1360 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1363 int nbOfCells=getNumberOfCells();
1366 int initMeshLgth=getNodalConnectivityArrayLen();
1367 int *conn=_nodal_connec->getPointer();
1368 int *index=_nodal_connec_index->getPointer();
1373 for(int i=0;i<nbOfCells;i++)
1375 lgthOfCurCell=index[i+1]-posOfCurCell;
1376 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1377 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1378 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1382 switch(cm.getDimension())
1386 INTERP_KERNEL::AutoPtr<int> tmp=new int[lgthOfCurCell-1];
1387 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(int *)tmp);
1388 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1393 int nbOfFaces,lgthOfPolyhConn;
1394 INTERP_KERNEL::AutoPtr<int> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1395 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1400 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1404 ret=ret || (newType!=type);
1405 conn[newPos]=newType;
1407 posOfCurCell=index[i+1];
1412 std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1413 newPos+=lgthOfCurCell;
1414 posOfCurCell+=lgthOfCurCell;
1418 if(newPos!=initMeshLgth)
1419 _nodal_connec->reAlloc(newPos);
1426 * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1427 * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1428 * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells.
1430 * \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
1433 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1435 checkFullyDefined();
1436 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1437 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1438 MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1439 coords->recenterForMaxPrecision(eps);
1441 int nbOfCells=getNumberOfCells();
1442 const int *conn=_nodal_connec->getConstPointer();
1443 const int *index=_nodal_connec_index->getConstPointer();
1444 MCAuto<DataArrayInt> connINew=DataArrayInt::New();
1445 connINew->alloc(nbOfCells+1,1);
1446 int *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1447 MCAuto<DataArrayInt> connNew=DataArrayInt::New(); connNew->alloc(0,1);
1449 for(int i=0;i<nbOfCells;i++,connINewPtr++)
1451 if(conn[index[i]]==(int)INTERP_KERNEL::NORM_POLYHED)
1453 SimplifyPolyhedronCell(eps,coords,conn+index[i],conn+index[i+1],connNew);
1457 connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1458 *connINewPtr=connNew->getNumberOfTuples();
1461 setConnectivity(connNew,connINew,false);
1465 * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1466 * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1467 * the format of the returned DataArrayInt instance.
1469 * \return a newly allocated DataArrayInt sorted ascendingly of fetched node ids.
1470 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1472 DataArrayInt *MEDCouplingUMesh::computeFetchedNodeIds() const
1474 checkConnectivityFullyDefined();
1475 const int *maxEltPt(std::max_element(_nodal_connec->begin(),_nodal_connec->end()));
1476 int maxElt(maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1);
1477 std::vector<bool> retS(maxElt,false);
1478 computeNodeIdsAlg(retS);
1479 return DataArrayInt::BuildListOfSwitchedOn(retS);
1483 * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1484 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1486 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1488 int nbOfNodes((int)nodeIdsInUse.size()),nbOfCells(getNumberOfCells());
1489 const int *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1490 for(int i=0;i<nbOfCells;i++)
1491 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1494 if(conn[j]<nbOfNodes)
1495 nodeIdsInUse[conn[j]]=true;
1498 std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1499 throw INTERP_KERNEL::Exception(oss.str());
1505 * Finds nodes not used in any cell and returns an array giving a new id to every node
1506 * by excluding the unused nodes, for which the array holds -1. The result array is
1507 * a mapping in "Old to New" mode.
1508 * \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1509 * \return DataArrayInt * - a new instance of DataArrayInt. Its length is \a
1510 * this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1511 * if the node is unused or a new id else. The caller is to delete this
1512 * array using decrRef() as it is no more needed.
1513 * \throw If the coordinates array is not set.
1514 * \throw If the nodal connectivity of cells is not defined.
1515 * \throw If the nodal connectivity includes an invalid id.
1517 * \if ENABLE_EXAMPLES
1518 * \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1519 * \ref py_mcumesh_getNodeIdsInUse "Here is a Python example".
1521 * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1523 DataArrayInt *MEDCouplingUMesh::getNodeIdsInUse(int& nbrOfNodesInUse) const
1526 int nbOfNodes(getNumberOfNodes());
1527 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1528 ret->alloc(nbOfNodes,1);
1529 int *traducer=ret->getPointer();
1530 std::fill(traducer,traducer+nbOfNodes,-1);
1531 int nbOfCells=getNumberOfCells();
1532 const int *connIndex=_nodal_connec_index->getConstPointer();
1533 const int *conn=_nodal_connec->getConstPointer();
1534 for(int i=0;i<nbOfCells;i++)
1535 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1538 if(conn[j]<nbOfNodes)
1539 traducer[conn[j]]=1;
1542 std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1543 throw INTERP_KERNEL::Exception(oss.str());
1546 nbrOfNodesInUse=(int)std::count(traducer,traducer+nbOfNodes,1);
1547 std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1552 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1553 * For each cell in \b this the number of nodes constituting cell is computed.
1554 * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1555 * So for pohyhedrons some nodes can be counted several times in the returned result.
1557 * \return a newly allocated array
1558 * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1560 DataArrayInt *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1562 checkConnectivityFullyDefined();
1563 int nbOfCells=getNumberOfCells();
1564 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1565 ret->alloc(nbOfCells,1);
1566 int *retPtr=ret->getPointer();
1567 const int *conn=getNodalConnectivity()->getConstPointer();
1568 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1569 for(int i=0;i<nbOfCells;i++,retPtr++)
1571 if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1572 *retPtr=connI[i+1]-connI[i]-1;
1574 *retPtr=connI[i+1]-connI[i]-1-std::count(conn+connI[i]+1,conn+connI[i+1],-1);
1580 * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1581 * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1583 * \return DataArrayInt * - new object to be deallocated by the caller.
1584 * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1586 DataArrayInt *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1588 checkConnectivityFullyDefined();
1589 int nbOfCells=getNumberOfCells();
1590 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1591 ret->alloc(nbOfCells,1);
1592 int *retPtr=ret->getPointer();
1593 const int *conn=getNodalConnectivity()->getConstPointer();
1594 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1595 for(int i=0;i<nbOfCells;i++,retPtr++)
1597 std::set<int> s(conn+connI[i]+1,conn+connI[i+1]);
1598 if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1599 *retPtr=(int)s.size();
1603 *retPtr=(int)s.size();
1610 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1611 * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1613 * \return a newly allocated array
1615 DataArrayInt *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1617 checkConnectivityFullyDefined();
1618 int nbOfCells=getNumberOfCells();
1619 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1620 ret->alloc(nbOfCells,1);
1621 int *retPtr=ret->getPointer();
1622 const int *conn=getNodalConnectivity()->getConstPointer();
1623 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1624 for(int i=0;i<nbOfCells;i++,retPtr++,connI++)
1626 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1627 *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1633 * Removes unused nodes (the node coordinates array is shorten) and returns an array
1634 * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1635 * array mean that the corresponding old node is no more used.
1636 * \return DataArrayInt * - a new instance of DataArrayInt of length \a
1637 * this->getNumberOfNodes() before call of this method. The caller is to
1638 * delete this array using decrRef() as it is no more needed.
1639 * \throw If the coordinates array is not set.
1640 * \throw If the nodal connectivity of cells is not defined.
1641 * \throw If the nodal connectivity includes an invalid id.
1642 * \sa areAllNodesFetched
1644 * \if ENABLE_EXAMPLES
1645 * \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1646 * \ref py_mcumesh_zipCoordsTraducer "Here is a Python example".
1649 DataArrayInt *MEDCouplingUMesh::zipCoordsTraducer()
1651 return MEDCouplingPointSet::zipCoordsTraducer();
1655 * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1656 * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1658 int MEDCouplingUMesh::AreCellsEqual(const int *conn, const int *connI, int cell1, int cell2, int compType)
1663 return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1665 return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1667 return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1669 return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1671 return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1673 throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1677 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1679 int MEDCouplingUMesh::AreCellsEqualPolicy0(const int *conn, const int *connI, int cell1, int cell2)
1681 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1682 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1687 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1689 int MEDCouplingUMesh::AreCellsEqualPolicy1(const int *conn, const int *connI, int cell1, int cell2)
1691 int sz=connI[cell1+1]-connI[cell1];
1692 if(sz==connI[cell2+1]-connI[cell2])
1694 if(conn[connI[cell1]]==conn[connI[cell2]])
1696 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1697 unsigned dim=cm.getDimension();
1703 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1704 int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1705 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1706 work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1707 return work!=tmp+sz1?1:0;
1710 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1713 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1720 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1722 int MEDCouplingUMesh::AreCellsEqualPolicy2(const int *conn, const int *connI, int cell1, int cell2)
1724 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1726 if(conn[connI[cell1]]==conn[connI[cell2]])
1728 std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1729 std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1737 * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1739 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const int *conn, const int *connI, int cell1, int cell2)
1741 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1743 std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1744 std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1751 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1753 int MEDCouplingUMesh::AreCellsEqualPolicy7(const int *conn, const int *connI, int cell1, int cell2)
1755 int sz=connI[cell1+1]-connI[cell1];
1756 if(sz==connI[cell2+1]-connI[cell2])
1758 if(conn[connI[cell1]]==conn[connI[cell2]])
1760 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1761 unsigned dim=cm.getDimension();
1767 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1768 int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1769 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1770 work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1775 std::reverse_iterator<int *> it1((int *)tmp+sz1);
1776 std::reverse_iterator<int *> it2((int *)tmp);
1777 if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1783 return work!=tmp+sz1?1:0;
1786 {//case of SEG2 and SEG3
1787 if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1789 if(!cm.isQuadratic())
1791 std::reverse_iterator<const int *> it1(conn+connI[cell1+1]);
1792 std::reverse_iterator<const int *> it2(conn+connI[cell1]+1);
1793 if(std::equal(it1,it2,conn+connI[cell2]+1))
1799 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])
1806 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1813 * This method find in candidate pool defined by 'candidates' the cells equal following the polycy 'compType'.
1814 * If any true is returned and the results will be put at the end of 'result' output parameter. If not false is returned
1815 * and result remains unchanged.
1816 * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1817 * If in 'candidates' pool -1 value is considered as an empty value.
1818 * WARNING this method returns only ONE set of result !
1820 bool MEDCouplingUMesh::AreCellsEqualInPool(const std::vector<int>& candidates, int compType, const int *conn, const int *connI, DataArrayInt *result)
1822 if(candidates.size()<1)
1825 std::vector<int>::const_iterator iter=candidates.begin();
1826 int start=(*iter++);
1827 for(;iter!=candidates.end();iter++)
1829 int status=AreCellsEqual(conn,connI,start,*iter,compType);
1834 result->pushBackSilent(start);
1838 result->pushBackSilent(*iter);
1840 result->pushBackSilent(status==2?(*iter+1):-(*iter+1));
1847 * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified
1849 * This method keeps the coordiantes of \a this. This method is time consuming.
1851 * \param [in] compType input specifying the technique used to compare cells each other.
1852 * - 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.
1853 * - 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)
1854 * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1855 * - 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
1856 * can be used for users not sensitive to orientation of cell
1857 * \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.
1858 * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1859 * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1860 * \return the correspondance array old to new in a newly allocated array.
1863 void MEDCouplingUMesh::findCommonCells(int compType, int startCellId, DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr) const
1865 MCAuto<DataArrayInt> revNodal=DataArrayInt::New(),revNodalI=DataArrayInt::New();
1866 getReverseNodalConnectivity(revNodal,revNodalI);
1867 FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1870 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, int startCellId, const DataArrayInt *nodal, const DataArrayInt *nodalI, const DataArrayInt *revNodal, const DataArrayInt *revNodalI,
1871 DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr)
1873 MCAuto<DataArrayInt> commonCells=DataArrayInt::New(),commonCellsI=DataArrayInt::New(); commonCells->alloc(0,1);
1874 int nbOfCells=nodalI->getNumberOfTuples()-1;
1875 commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1876 const int *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1877 const int *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1878 std::vector<bool> isFetched(nbOfCells,false);
1881 for(int i=0;i<nbOfCells;i++)
1885 const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1886 std::vector<int> v,v2;
1887 if(connOfNode!=connPtr+connIPtr[i+1])
1889 const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1890 v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1893 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1897 const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1898 std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1899 v2.resize(std::distance(v2.begin(),it));
1903 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1905 int pos=commonCellsI->back();
1906 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1907 for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1908 isFetched[*it]=true;
1916 for(int i=startCellId;i<nbOfCells;i++)
1920 const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1921 std::vector<int> v,v2;
1922 if(connOfNode!=connPtr+connIPtr[i+1])
1924 v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1927 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1931 std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1932 v2.resize(std::distance(v2.begin(),it));
1936 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1938 int pos=commonCellsI->back();
1939 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1940 for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1941 isFetched[*it]=true;
1947 commonCellsArr=commonCells.retn();
1948 commonCellsIArr=commonCellsI.retn();
1952 * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1953 * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1954 * than \a this->getNumberOfCells() in the returned array means that there is no
1955 * corresponding cell in \a this mesh.
1956 * It is expected that \a this and \a other meshes share the same node coordinates
1957 * array, if it is not so an exception is thrown.
1958 * \param [in] other - the mesh to compare with.
1959 * \param [in] compType - specifies a cell comparison technique. For meaning of its
1960 * valid values [0,1,2], see zipConnectivityTraducer().
1961 * \param [out] arr - a new instance of DataArrayInt returning correspondence
1962 * between cells of the two meshes. It contains \a other->getNumberOfCells()
1963 * values. The caller is to delete this array using
1964 * decrRef() as it is no more needed.
1965 * \return bool - \c true if all cells of \a other mesh are present in the \a this
1968 * \if ENABLE_EXAMPLES
1969 * \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1970 * \ref py_mcumesh_areCellsIncludedIn "Here is a Python example".
1972 * \sa checkDeepEquivalOnSameNodesWith()
1973 * \sa checkGeoEquivalWith()
1975 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayInt *& arr) const
1977 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1978 int nbOfCells=getNumberOfCells();
1979 static const int possibleCompType[]={0,1,2};
1980 if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1982 std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1983 std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1985 throw INTERP_KERNEL::Exception(oss.str());
1987 MCAuto<DataArrayInt> o2n=mesh->zipConnectivityTraducer(compType,nbOfCells);
1988 arr=o2n->subArray(nbOfCells);
1989 arr->setName(other->getName());
1991 if(other->getNumberOfCells()==0)
1993 return arr->getMaxValue(tmp)<nbOfCells;
1997 * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1998 * This method tries to determine if \b other is fully included in \b this.
1999 * The main difference is that this method is not expected to throw exception.
2000 * This method has two outputs :
2002 * \param other other mesh
2003 * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
2004 * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
2006 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayInt *& arr) const
2008 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
2009 DataArrayInt *commonCells=0,*commonCellsI=0;
2010 int thisNbCells=getNumberOfCells();
2011 mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
2012 MCAuto<DataArrayInt> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
2013 const int *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
2014 int otherNbCells=other->getNumberOfCells();
2015 MCAuto<DataArrayInt> arr2=DataArrayInt::New();
2016 arr2->alloc(otherNbCells,1);
2017 arr2->fillWithZero();
2018 int *arr2Ptr=arr2->getPointer();
2019 int nbOfCommon=commonCellsI->getNumberOfTuples()-1;
2020 for(int i=0;i<nbOfCommon;i++)
2022 int start=commonCellsPtr[commonCellsIPtr[i]];
2023 if(start<thisNbCells)
2025 for(int j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
2027 int sig=commonCellsPtr[j]>0?1:-1;
2028 int val=std::abs(commonCellsPtr[j])-1;
2029 if(val>=thisNbCells)
2030 arr2Ptr[val-thisNbCells]=sig*(start+1);
2034 arr2->setName(other->getName());
2035 if(arr2->presenceOfValue(0))
2041 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
2044 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
2045 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
2047 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
2048 std::vector<const MEDCouplingUMesh *> ms(2);
2051 return MergeUMeshesOnSameCoords(ms);
2055 * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
2056 * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
2057 * cellIds is not given explicitely but by a range python like.
2062 * \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.
2063 * \return a newly allocated
2065 * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
2066 * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
2068 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(int start, int end, int step, bool keepCoords) const
2070 if(getMeshDimension()!=-1)
2071 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
2074 int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
2076 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2078 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2080 return const_cast<MEDCouplingUMesh *>(this);
2085 * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
2086 * The result mesh shares or not the node coordinates array with \a this mesh depending
2087 * on \a keepCoords parameter.
2088 * \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
2089 * to write this mesh to the MED file, its cells must be sorted using
2090 * sortCellsInMEDFileFrmt().
2091 * \param [in] begin - an array of cell ids to include to the new mesh.
2092 * \param [in] end - a pointer to last-plus-one-th element of \a begin.
2093 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2094 * array of \a this mesh, else "free" nodes are removed from the result mesh
2095 * by calling zipCoords().
2096 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2097 * to delete this mesh using decrRef() as it is no more needed.
2098 * \throw If the coordinates array is not set.
2099 * \throw If the nodal connectivity of cells is not defined.
2100 * \throw If any cell id in the array \a begin is not valid.
2102 * \if ENABLE_EXAMPLES
2103 * \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
2104 * \ref py_mcumesh_buildPartOfMySelf "Here is a Python example".
2107 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const int *begin, const int *end, bool keepCoords) const
2109 if(getMeshDimension()!=-1)
2110 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
2114 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2116 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2118 return const_cast<MEDCouplingUMesh *>(this);
2123 * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
2125 * 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.
2126 * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
2127 * The number of cells of \b this will remain the same with this method.
2129 * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
2130 * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
2131 * \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 ).
2132 * Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
2134 void MEDCouplingUMesh::setPartOfMySelf(const int *cellIdsBg, const int *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2136 checkConnectivityFullyDefined();
2137 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2138 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2139 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2140 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2142 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2143 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2144 throw INTERP_KERNEL::Exception(oss.str());
2146 int nbOfCellsToModify=(int)std::distance(cellIdsBg,cellIdsEnd);
2147 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2149 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2150 throw INTERP_KERNEL::Exception(oss.str());
2152 int nbOfCells=getNumberOfCells();
2153 bool easyAssign=true;
2154 const int *connI=_nodal_connec_index->getConstPointer();
2155 const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2156 for(const int *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2158 if(*it>=0 && *it<nbOfCells)
2160 easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2164 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2165 throw INTERP_KERNEL::Exception(oss.str());
2170 MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2175 DataArrayInt *arrOut=0,*arrIOut=0;
2176 MEDCouplingUMesh::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2178 MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2179 setConnectivity(arrOut,arrIOut,true);
2183 void MEDCouplingUMesh::setPartOfMySelfSlice(int start, int end, int step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2185 checkConnectivityFullyDefined();
2186 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2187 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2188 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2189 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2191 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2192 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2193 throw INTERP_KERNEL::Exception(oss.str());
2195 int nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2196 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2198 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2199 throw INTERP_KERNEL::Exception(oss.str());
2201 int nbOfCells=getNumberOfCells();
2202 bool easyAssign=true;
2203 const int *connI=_nodal_connec_index->getConstPointer();
2204 const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2206 for(int i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2208 if(it>=0 && it<nbOfCells)
2210 easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2214 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2215 throw INTERP_KERNEL::Exception(oss.str());
2220 MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2225 DataArrayInt *arrOut=0,*arrIOut=0;
2226 MEDCouplingUMesh::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2228 MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2229 setConnectivity(arrOut,arrIOut,true);
2234 * Keeps from \a this only cells which constituing point id are in the ids specified by [ \a begin,\a end ).
2235 * The resulting cell ids are stored at the end of the 'cellIdsKept' parameter.
2236 * Parameter \a fullyIn specifies if a cell that has part of its nodes in ids array is kept or not.
2237 * If \a fullyIn is true only cells whose ids are \b fully contained in [ \a begin,\a end ) tab will be kept.
2239 * \param [in] begin input start of array of node ids.
2240 * \param [in] end input end of array of node ids.
2241 * \param [in] fullyIn input that specifies if all node ids must be in [ \a begin,\a end ) array to consider cell to be in.
2242 * \param [in,out] cellIdsKeptArr array where all candidate cell ids are put at the end.
2244 void MEDCouplingUMesh::fillCellIdsToKeepFromNodeIds(const int *begin, const int *end, bool fullyIn, DataArrayInt *&cellIdsKeptArr) const
2246 MCAuto<DataArrayInt> cellIdsKept=DataArrayInt::New(); cellIdsKept->alloc(0,1);
2247 checkConnectivityFullyDefined();
2249 int sz=getNodalConnectivity()->getMaxValue(tmp); sz=std::max(sz,0)+1;
2250 std::vector<bool> fastFinder(sz,false);
2251 for(const int *work=begin;work!=end;work++)
2252 if(*work>=0 && *work<sz)
2253 fastFinder[*work]=true;
2254 int nbOfCells=getNumberOfCells();
2255 const int *conn=getNodalConnectivity()->getConstPointer();
2256 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2257 for(int i=0;i<nbOfCells;i++)
2259 int ref=0,nbOfHit=0;
2260 for(const int *work2=conn+connIndex[i]+1;work2!=conn+connIndex[i+1];work2++)
2264 if(fastFinder[*work2])
2267 if((ref==nbOfHit && fullyIn) || (nbOfHit!=0 && !fullyIn))
2268 cellIdsKept->pushBackSilent(i);
2270 cellIdsKeptArr=cellIdsKept.retn();
2274 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2275 * this->getMeshDimension(), that bound some cells of \a this mesh.
2276 * The cells of lower dimension to include to the result mesh are selected basing on
2277 * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2278 * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2279 * ==\c false, a cell is copied if any its node is in the array of node ids. The
2280 * created mesh shares the node coordinates array with \a this mesh.
2281 * \param [in] begin - the array of node ids.
2282 * \param [in] end - a pointer to the (last+1)-th element of \a begin.
2283 * \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2284 * array \a begin are added, else cells whose any node is in the
2285 * array \a begin are added.
2286 * \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2287 * to delete this mesh using decrRef() as it is no more needed.
2288 * \throw If the coordinates array is not set.
2289 * \throw If the nodal connectivity of cells is not defined.
2290 * \throw If any node id in \a begin is not valid.
2292 * \if ENABLE_EXAMPLES
2293 * \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2294 * \ref py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2297 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const int *begin, const int *end, bool fullyIn) const
2299 MCAuto<DataArrayInt> desc,descIndx,revDesc,revDescIndx;
2300 desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=DataArrayInt::New(); revDescIndx=DataArrayInt::New();
2301 MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2302 desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2303 return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2307 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2308 * this->getMeshDimension(), which bound only one cell of \a this mesh.
2309 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2310 * array of \a this mesh, else "free" nodes are removed from the result mesh
2311 * by calling zipCoords().
2312 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2313 * to delete this mesh using decrRef() as it is no more needed.
2314 * \throw If the coordinates array is not set.
2315 * \throw If the nodal connectivity of cells is not defined.
2317 * \if ENABLE_EXAMPLES
2318 * \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2319 * \ref py_mcumesh_buildBoundaryMesh "Here is a Python example".
2322 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2324 DataArrayInt *desc=DataArrayInt::New();
2325 DataArrayInt *descIndx=DataArrayInt::New();
2326 DataArrayInt *revDesc=DataArrayInt::New();
2327 DataArrayInt *revDescIndx=DataArrayInt::New();
2329 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2332 descIndx->decrRef();
2333 int nbOfCells=meshDM1->getNumberOfCells();
2334 const int *revDescIndxC=revDescIndx->getConstPointer();
2335 std::vector<int> boundaryCells;
2336 for(int i=0;i<nbOfCells;i++)
2337 if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2338 boundaryCells.push_back(i);
2339 revDescIndx->decrRef();
2340 MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2345 * This method returns a newly created DataArrayInt instance containing ids of cells located in boundary.
2346 * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2347 * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2349 DataArrayInt *MEDCouplingUMesh::findCellIdsOnBoundary() const
2351 checkFullyDefined();
2352 MCAuto<DataArrayInt> desc=DataArrayInt::New();
2353 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2354 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2355 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2357 buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2358 desc=(DataArrayInt*)0; descIndx=(DataArrayInt*)0;
2360 MCAuto<DataArrayInt> tmp=revDescIndx->deltaShiftIndex();
2361 MCAuto<DataArrayInt> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayInt*)0;
2362 const int *revDescPtr=revDesc->getConstPointer();
2363 const int *revDescIndxPtr=revDescIndx->getConstPointer();
2364 int nbOfCells=getNumberOfCells();
2365 std::vector<bool> ret1(nbOfCells,false);
2367 for(const int *pt=faceIds->begin();pt!=faceIds->end();pt++)
2368 if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2369 { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2371 DataArrayInt *ret2=DataArrayInt::New();
2373 int *ret2Ptr=ret2->getPointer();
2375 for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2378 ret2->setName("BoundaryCells");
2383 * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2384 * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2385 * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2386 * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2388 * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2389 * 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
2390 * equals a cell in \b otherDimM1OnSameCoords.
2392 * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2393 * are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2395 * \param [in] otherDimM1OnSameCoords
2396 * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2397 * \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
2398 * cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2400 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *&cellIdsRk0, DataArrayInt *&cellIdsRk1) const
2402 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2403 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2404 checkConnectivityFullyDefined();
2405 otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2406 if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2407 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2408 MCAuto<DataArrayInt> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2409 MCAuto<DataArrayInt> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2410 MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2411 MCAuto<DataArrayInt> descThisPart=DataArrayInt::New(),descIThisPart=DataArrayInt::New(),revDescThisPart=DataArrayInt::New(),revDescIThisPart=DataArrayInt::New();
2412 MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2413 const int *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2414 DataArrayInt *idsOtherInConsti=0;
2415 bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2416 MCAuto<DataArrayInt> idsOtherInConstiAuto(idsOtherInConsti);
2418 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2420 for(const int *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2421 s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2422 MCAuto<DataArrayInt> s1arr_renum1=DataArrayInt::New(); s1arr_renum1->alloc((int)s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2423 s1arr_renum1->sort();
2424 cellIdsRk0=s0arr.retn();
2425 //cellIdsRk1=s_renum1.retn();
2426 cellIdsRk1=s1arr_renum1.retn();
2430 * 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
2431 * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2433 * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2435 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2437 MCAuto<DataArrayInt> desc=DataArrayInt::New();
2438 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2439 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2440 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2442 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2443 revDesc=0; desc=0; descIndx=0;
2444 MCAuto<DataArrayInt> revDescIndx2=revDescIndx->deltaShiftIndex();
2445 MCAuto<DataArrayInt> part=revDescIndx2->findIdsEqual(1);
2446 return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2450 * Finds nodes lying on the boundary of \a this mesh.
2451 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of found
2452 * nodes. The caller is to delete this array using decrRef() as it is no
2454 * \throw If the coordinates array is not set.
2455 * \throw If the nodal connectivity of cells is node defined.
2457 * \if ENABLE_EXAMPLES
2458 * \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2459 * \ref py_mcumesh_findBoundaryNodes "Here is a Python example".
2462 DataArrayInt *MEDCouplingUMesh::findBoundaryNodes() const
2464 MCAuto<MEDCouplingUMesh> skin=computeSkin();
2465 return skin->computeFetchedNodeIds();
2468 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2471 return const_cast<MEDCouplingUMesh *>(this);
2475 * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2476 * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2477 * 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.
2478 * 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.
2479 * 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.
2481 * \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
2482 * parameter is altered during the call.
2483 * \param [out] nodeIdsToDuplicate node ids needed to be duplicated following the algorithm explain above.
2484 * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2485 * \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.
2487 * \warning This method modifies param \b otherDimM1OnSameCoords (for speed reasons).
2489 void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *& nodeIdsToDuplicate,
2490 DataArrayInt *& cellIdsNeededToBeRenum, DataArrayInt *& cellIdsNotModified) const
2492 typedef MCAuto<DataArrayInt> DAInt;
2493 typedef MCAuto<MEDCouplingUMesh> MCUMesh;
2495 checkFullyDefined();
2496 otherDimM1OnSameCoords.checkFullyDefined();
2497 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2498 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2499 if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2500 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2502 // Checking star-shaped M1 group:
2503 DAInt dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2504 MCUMesh meshM2 = otherDimM1OnSameCoords.buildDescendingConnectivity(dt0, dit0, rdt0, rdit0);
2505 DAInt dsi = rdit0->deltaShiftIndex();
2506 DAInt idsTmp0 = dsi->findIdsNotInRange(-1, 3);
2507 if(idsTmp0->getNumberOfTuples())
2508 throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2509 dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2511 // Get extreme nodes from the group (they won't be duplicated), ie nodes belonging to boundary cells of M1
2512 DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2513 MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2514 DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2515 // Remove from the list points on the boundary of the M0 mesh (those need duplication!)
2516 dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2517 MCUMesh m0desc = buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0;
2518 dsi = rdit0->deltaShiftIndex();
2519 DAInt boundSegs = dsi->findIdsEqual(1); // boundary segs/faces of the M0 mesh
2520 MCUMesh m0descSkin = static_cast<MEDCouplingUMesh *>(m0desc->buildPartOfMySelf(boundSegs->begin(),boundSegs->end(), true));
2521 DAInt fNodes = m0descSkin->computeFetchedNodeIds();
2522 // In 3D, some points on the boundary of M0 still need duplication:
2524 if (getMeshDimension() == 3)
2526 DAInt dnu1=DataArrayInt::New(), dnu2=DataArrayInt::New(), dnu3=DataArrayInt::New(), dnu4=DataArrayInt::New();
2527 MCUMesh m0descSkinDesc = m0descSkin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4);
2528 dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2529 DataArrayInt * corresp=0;
2530 meshM2->areCellsIncludedIn(m0descSkinDesc,2,corresp);
2531 DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2533 if (validIds->getNumberOfTuples())
2535 MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0descSkinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2536 DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2537 DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2538 notDup = xtrem->buildSubstraction(fNodes1);
2541 notDup = xtrem->buildSubstraction(fNodes);
2544 notDup = xtrem->buildSubstraction(fNodes);
2546 // Now compute cells around group (i.e. cells where we will do the propagation to identify the two sub-sets delimited by the group)
2547 DAInt m1Nodes = otherDimM1OnSameCoords.computeFetchedNodeIds();
2548 DAInt dupl = m1Nodes->buildSubstraction(notDup);
2549 DAInt cellsAroundGroup = getCellIdsLyingOnNodes(dupl->begin(), dupl->end(), false); // false= take cell in, even if not all nodes are in notDup
2552 MCUMesh m0Part2=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroup->begin(),cellsAroundGroup->end(),true));
2553 int nCells2 = m0Part2->getNumberOfCells();
2554 DAInt desc00=DataArrayInt::New(),descI00=DataArrayInt::New(),revDesc00=DataArrayInt::New(),revDescI00=DataArrayInt::New();
2555 MCUMesh m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00);
2557 // Neighbor information of the mesh without considering the crack (serves to count how many connex pieces it is made of)
2558 DataArrayInt *tmp00=0,*tmp11=0;
2559 MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00, tmp00, tmp11);
2560 DAInt neighInit00(tmp00);
2561 DAInt neighIInit00(tmp11);
2562 // Neighbor information of the mesh WITH the crack (some neighbors are removed):
2563 DataArrayInt *idsTmp=0;
2564 bool b=m01->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsTmp);
2566 // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2567 // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2568 MEDCouplingUMesh::RemoveIdsFromIndexedArrays(ids->begin(),ids->end(),desc00,descI00);
2569 DataArrayInt *tmp0=0,*tmp1=0;
2570 // Compute the neighbor of each cell in m0Part2, taking into account the broken link above. Two
2571 // cells on either side of the crack (defined by the mesh of low dimension) are not neighbor anymore.
2572 ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00,tmp0,tmp1);
2573 DAInt neigh00(tmp0);
2574 DAInt neighI00(tmp1);
2576 // For each initial connex part of the sub-mesh (or said differently for each independent crack):
2577 int seed = 0, nIter = 0;
2578 int nIterMax = nCells2+1; // Safety net for the loop
2579 DAInt hitCells = DataArrayInt::New(); hitCells->alloc(nCells2);
2580 hitCells->fillWithValue(-1);
2581 DAInt cellsToModifyConn0_torenum = DataArrayInt::New();
2582 cellsToModifyConn0_torenum->alloc(0,1);
2583 while (nIter < nIterMax)
2585 DAInt t = hitCells->findIdsEqual(-1);
2586 if (!t->getNumberOfTuples())
2588 // Connex zone without the crack (to compute the next seed really)
2590 DAInt connexCheck = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neighInit00,neighIInit00, -1, dnu);
2592 for (int * ptr = connexCheck->getPointer(); cnt < connexCheck->getNumberOfTuples(); ptr++, cnt++)
2593 hitCells->setIJ(*ptr,0,1);
2594 // Connex zone WITH the crack (to identify cells lying on either part of the crack)
2595 DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neigh00,neighI00, -1, dnu);
2596 cellsToModifyConn0_torenum = DataArrayInt::Aggregate(cellsToModifyConn0_torenum, spreadZone, 0);
2597 // Compute next seed, i.e. a cell in another connex part, which was not covered by the previous iterations
2598 DAInt comple = cellsToModifyConn0_torenum->buildComplement(nCells2);
2599 DAInt nonHitCells = hitCells->findIdsEqual(-1);
2600 DAInt intersec = nonHitCells->buildIntersection(comple);
2601 if (intersec->getNumberOfTuples())
2602 { seed = intersec->getIJ(0,0); }
2607 if (nIter >= nIterMax)
2608 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate(): internal error - too many iterations.");
2610 DAInt cellsToModifyConn1_torenum=cellsToModifyConn0_torenum->buildComplement(neighI00->getNumberOfTuples()-1);
2611 cellsToModifyConn0_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2612 cellsToModifyConn1_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2614 cellIdsNeededToBeRenum=cellsToModifyConn0_torenum.retn();
2615 cellIdsNotModified=cellsToModifyConn1_torenum.retn();
2616 nodeIdsToDuplicate=dupl.retn();
2620 * This method operates a modification of the connectivity and coords in \b this.
2621 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2622 * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2623 * 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
2624 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2625 * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2627 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2629 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2630 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2632 void MEDCouplingUMesh::duplicateNodes(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd)
2634 int nbOfNodes=getNumberOfNodes();
2635 duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2636 duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2640 * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2641 * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2643 * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2645 * \sa renumberNodesInConn
2647 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(int offset)
2649 checkConnectivityFullyDefined();
2650 int *conn(getNodalConnectivity()->getPointer());
2651 const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2652 int nbOfCells(getNumberOfCells());
2653 for(int i=0;i<nbOfCells;i++)
2654 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2656 int& node=conn[iconn];
2657 if(node>=0)//avoid polyhedron separator
2662 _nodal_connec->declareAsNew();
2667 * Same than renumberNodesInConn(const int *) except that here the format of old-to-new traducer is using map instead
2668 * 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
2671 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<int,int>& newNodeNumbersO2N)
2673 checkConnectivityFullyDefined();
2674 int *conn(getNodalConnectivity()->getPointer());
2675 const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2676 int nbOfCells(getNumberOfCells());
2677 for(int i=0;i<nbOfCells;i++)
2678 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2680 int& node=conn[iconn];
2681 if(node>=0)//avoid polyhedron separator
2683 INTERP_KERNEL::HashMap<int,int>::const_iterator it(newNodeNumbersO2N.find(node));
2684 if(it!=newNodeNumbersO2N.end())
2690 std::ostringstream oss; oss << "MEDCouplingUMesh::renumberNodesInConn(map) : presence in connectivity for cell #" << i << " of node #" << node << " : Not in map !";
2691 throw INTERP_KERNEL::Exception(oss.str());
2695 _nodal_connec->declareAsNew();
2700 * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2701 * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2702 * This method is a generalization of shiftNodeNumbersInConn().
2703 * \warning This method performs no check of validity of new ids. **Use it with care !**
2704 * \param [in] newNodeNumbersO2N - a permutation array, of length \a
2705 * this->getNumberOfNodes(), in "Old to New" mode.
2706 * See \ref numbering for more info on renumbering modes.
2707 * \throw If the nodal connectivity of cells is not defined.
2709 * \if ENABLE_EXAMPLES
2710 * \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2711 * \ref py_mcumesh_renumberNodesInConn "Here is a Python example".
2714 void MEDCouplingUMesh::renumberNodesInConn(const int *newNodeNumbersO2N)
2716 checkConnectivityFullyDefined();
2717 int *conn=getNodalConnectivity()->getPointer();
2718 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2719 int nbOfCells(getNumberOfCells());
2720 for(int i=0;i<nbOfCells;i++)
2721 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2723 int& node=conn[iconn];
2724 if(node>=0)//avoid polyhedron separator
2726 node=newNodeNumbersO2N[node];
2729 _nodal_connec->declareAsNew();
2734 * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2735 * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2736 * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2738 * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2740 void MEDCouplingUMesh::shiftNodeNumbersInConn(int delta)
2742 checkConnectivityFullyDefined();
2743 int *conn=getNodalConnectivity()->getPointer();
2744 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2745 int nbOfCells=getNumberOfCells();
2746 for(int i=0;i<nbOfCells;i++)
2747 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2749 int& node=conn[iconn];
2750 if(node>=0)//avoid polyhedron separator
2755 _nodal_connec->declareAsNew();
2760 * This method operates a modification of the connectivity in \b this.
2761 * 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.
2762 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2763 * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2764 * 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
2765 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2766 * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2768 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2769 * As an another consequense after the call of this method \b this can be transiently non cohrent.
2771 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2772 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2773 * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ).
2775 void MEDCouplingUMesh::duplicateNodesInConn(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd, int offset)
2777 checkConnectivityFullyDefined();
2778 std::map<int,int> m;
2780 for(const int *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2782 int *conn=getNodalConnectivity()->getPointer();
2783 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2784 int nbOfCells=getNumberOfCells();
2785 for(int i=0;i<nbOfCells;i++)
2786 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2788 int& node=conn[iconn];
2789 if(node>=0)//avoid polyhedron separator
2791 std::map<int,int>::iterator it=m.find(node);
2800 * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2802 * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2803 * After the call of this method the number of cells remains the same as before.
2805 * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2806 * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2807 * be strictly in [0;this->getNumberOfCells()).
2809 * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2810 * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2811 * should be contained in[0;this->getNumberOfCells()).
2813 * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2816 void MEDCouplingUMesh::renumberCells(const int *old2NewBg, bool check)
2818 checkConnectivityFullyDefined();
2819 int nbCells=getNumberOfCells();
2820 const int *array=old2NewBg;
2822 array=DataArrayInt::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2824 const int *conn=_nodal_connec->getConstPointer();
2825 const int *connI=_nodal_connec_index->getConstPointer();
2826 MCAuto<DataArrayInt> o2n=DataArrayInt::New(); o2n->useArray(array,false,C_DEALLOC,nbCells,1);
2827 MCAuto<DataArrayInt> n2o=o2n->invertArrayO2N2N2O(nbCells);
2828 const int *n2oPtr=n2o->begin();
2829 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
2830 newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2831 newConn->copyStringInfoFrom(*_nodal_connec);
2832 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
2833 newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2834 newConnI->copyStringInfoFrom(*_nodal_connec_index);
2836 int *newC=newConn->getPointer();
2837 int *newCI=newConnI->getPointer();
2840 for(int i=0;i<nbCells;i++)
2843 int nbOfElts=connI[pos+1]-connI[pos];
2844 newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2849 setConnectivity(newConn,newConnI);
2851 free(const_cast<int *>(array));
2855 * Finds cells whose bounding boxes intersect a given bounding box.
2856 * \param [in] bbox - an array defining the bounding box via coordinates of its
2857 * extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2859 * \param [in] eps - a factor used to increase size of the bounding box of cell
2860 * before comparing it with \a bbox. This factor is multiplied by the maximal
2861 * extent of the bounding box of cell to produce an addition to this bounding box.
2862 * \return DataArrayInt * - a new instance of DataArrayInt holding ids for found
2863 * cells. The caller is to delete this array using decrRef() as it is no more
2865 * \throw If the coordinates array is not set.
2866 * \throw If the nodal connectivity of cells is not defined.
2868 * \if ENABLE_EXAMPLES
2869 * \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2870 * \ref py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2873 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
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(elem_bb, bbox, dim, eps))
2914 elems->pushBackSilent(ielem);
2916 return elems.retn();
2920 * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2921 * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2922 * added in 'elems' parameter.
2924 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2926 MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2927 if(getMeshDimension()==-1)
2929 elems->pushBackSilent(0);
2930 return elems.retn();
2932 int dim=getSpaceDimension();
2933 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2934 const int* conn = getNodalConnectivity()->getConstPointer();
2935 const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2936 const double* coords = getCoords()->getConstPointer();
2937 int nbOfCells=getNumberOfCells();
2938 for ( int ielem=0; ielem<nbOfCells;ielem++ )
2940 for (int i=0; i<dim; i++)
2942 elem_bb[i*2]=std::numeric_limits<double>::max();
2943 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2946 for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2948 int node= conn[inode];
2949 if(node>=0)//avoid polyhedron separator
2951 for (int idim=0; idim<dim; idim++)
2953 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2955 elem_bb[idim*2] = coords[node*dim+idim] ;
2957 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2959 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2964 if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
2965 elems->pushBackSilent(ielem);
2967 return elems.retn();
2971 * Returns a type of a cell by its id.
2972 * \param [in] cellId - the id of the cell of interest.
2973 * \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
2974 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2976 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(int cellId) const
2978 const int *ptI=_nodal_connec_index->getConstPointer();
2979 const int *pt=_nodal_connec->getConstPointer();
2980 if(cellId>=0 && cellId<(int)_nodal_connec_index->getNbOfElems()-1)
2981 return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2984 std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2985 throw INTERP_KERNEL::Exception(oss.str());
2990 * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2991 * This method does not throw exception if geometric type \a type is not in \a this.
2992 * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2993 * The coordinates array is not considered here.
2995 * \param [in] type the geometric type
2996 * \return cell ids in this having geometric type \a type.
2998 DataArrayInt *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
3001 MCAuto<DataArrayInt> ret=DataArrayInt::New();
3003 checkConnectivityFullyDefined();
3004 int nbCells=getNumberOfCells();
3005 int mdim=getMeshDimension();
3006 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
3007 if(mdim!=(int)cm.getDimension())
3008 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
3009 const int *ptI=_nodal_connec_index->getConstPointer();
3010 const int *pt=_nodal_connec->getConstPointer();
3011 for(int i=0;i<nbCells;i++)
3013 if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
3014 ret->pushBackSilent(i);
3020 * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
3022 int MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
3024 const int *ptI=_nodal_connec_index->getConstPointer();
3025 const int *pt=_nodal_connec->getConstPointer();
3026 int nbOfCells=getNumberOfCells();
3028 for(int i=0;i<nbOfCells;i++)
3029 if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
3035 * Returns the nodal connectivity of a given cell.
3036 * The separator of faces within polyhedron connectivity (-1) is not returned, thus
3037 * all returned node ids can be used in getCoordinatesOfNode().
3038 * \param [in] cellId - an id of the cell of interest.
3039 * \param [in,out] conn - a vector where the node ids are appended. It is not
3040 * cleared before the appending.
3041 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
3043 void MEDCouplingUMesh::getNodeIdsOfCell(int cellId, std::vector<int>& conn) const
3045 const int *ptI=_nodal_connec_index->getConstPointer();
3046 const int *pt=_nodal_connec->getConstPointer();
3047 for(const int *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
3052 std::string MEDCouplingUMesh::simpleRepr() const
3054 static const char msg0[]="No coordinates specified !";
3055 std::ostringstream ret;
3056 ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
3057 ret << "Description of mesh : \"" << getDescription() << "\"\n";
3059 double tt=getTime(tmpp1,tmpp2);
3060 ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
3061 ret << "Iteration : " << tmpp1 << " Order : " << tmpp2 << "\n";
3063 { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
3065 { ret << " Mesh dimension has not been set or is invalid !"; }
3068 const int spaceDim=getSpaceDimension();
3069 ret << spaceDim << "\nInfo attached on space dimension : ";
3070 for(int i=0;i<spaceDim;i++)
3071 ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
3075 ret << msg0 << "\n";
3076 ret << "Number of nodes : ";
3078 ret << getNumberOfNodes() << "\n";
3080 ret << msg0 << "\n";
3081 ret << "Number of cells : ";
3082 if(_nodal_connec!=0 && _nodal_connec_index!=0)
3083 ret << getNumberOfCells() << "\n";
3085 ret << "No connectivity specified !" << "\n";
3086 ret << "Cell types present : ";
3087 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
3089 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
3090 ret << cm.getRepr() << " ";
3096 std::string MEDCouplingUMesh::advancedRepr() const
3098 std::ostringstream ret;
3099 ret << simpleRepr();
3100 ret << "\nCoordinates array : \n___________________\n\n";
3102 _coords->reprWithoutNameStream(ret);
3104 ret << "No array set !\n";
3105 ret << "\n\nConnectivity arrays : \n_____________________\n\n";
3106 reprConnectivityOfThisLL(ret);
3111 * This method returns a C++ code that is a dump of \a this.
3112 * This method will throw if this is not fully defined.
3114 std::string MEDCouplingUMesh::cppRepr() const
3116 static const char coordsName[]="coords";
3117 static const char connName[]="conn";
3118 static const char connIName[]="connI";
3119 checkFullyDefined();
3120 std::ostringstream ret; ret << "// coordinates" << std::endl;
3121 _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
3122 _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
3123 _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
3124 ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
3125 ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
3126 ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
3127 ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
3131 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
3133 std::ostringstream ret;
3134 reprConnectivityOfThisLL(ret);
3139 * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsability to deal with.
3140 * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
3141 * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
3144 * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
3145 * 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
3146 * with number of tuples set to 0, if not the array is taken as this in the returned instance.
3148 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(int spaceDim) const
3150 int mdim=getMeshDimension();
3152 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
3153 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
3154 MCAuto<DataArrayInt> tmp1,tmp2;
3155 bool needToCpyCT=true;
3158 tmp1=DataArrayInt::New(); tmp1->alloc(0,1);
3166 if(!_nodal_connec_index)
3168 tmp2=DataArrayInt::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
3173 tmp2=_nodal_connec_index;
3176 ret->setConnectivity(tmp1,tmp2,false);
3181 MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
3182 ret->setCoords(coords);
3185 ret->setCoords(_coords);
3189 void MEDCouplingUMesh::reprConnectivityOfThisLL(std::ostringstream& stream) const
3191 if(_nodal_connec!=0 && _nodal_connec_index!=0)
3193 int nbOfCells=getNumberOfCells();
3194 const int *c=_nodal_connec->getConstPointer();
3195 const int *ci=_nodal_connec_index->getConstPointer();
3196 for(int i=0;i<nbOfCells;i++)
3198 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[i]]);
3199 stream << "Cell #" << i << " " << cm.getRepr() << " : ";
3200 std::copy(c+ci[i]+1,c+ci[i+1],std::ostream_iterator<int>(stream," "));
3205 stream << "Connectivity not defined !\n";
3208 int MEDCouplingUMesh::getNumberOfNodesInCell(int cellId) const
3210 const int *ptI=_nodal_connec_index->getConstPointer();
3211 const int *pt=_nodal_connec->getConstPointer();
3212 if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
3213 return ptI[cellId+1]-ptI[cellId]-1;
3215 return (int)std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind2nd(std::not_equal_to<int>(),-1));
3219 * Returns types of cells of the specified part of \a this mesh.
3220 * This method avoids computing sub-mesh explicitely to get its types.
3221 * \param [in] begin - an array of cell ids of interest.
3222 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3223 * \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3224 * describing the cell types.
3225 * \throw If the coordinates array is not set.
3226 * \throw If the nodal connectivity of cells is not defined.
3227 * \sa getAllGeoTypes()
3229 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const int *begin, const int *end) const
3231 checkFullyDefined();
3232 std::set<INTERP_KERNEL::NormalizedCellType> ret;
3233 const int *conn=_nodal_connec->getConstPointer();
3234 const int *connIndex=_nodal_connec_index->getConstPointer();
3235 for(const int *w=begin;w!=end;w++)
3236 ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3241 * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3242 * Optionally updates
3243 * a set of types of cells constituting \a this mesh.
3244 * This method is for advanced users having prepared their connectivity before. For
3245 * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3246 * \param [in] conn - the nodal connectivity array.
3247 * \param [in] connIndex - the nodal connectivity index array.
3248 * \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3251 void MEDCouplingUMesh::setConnectivity(DataArrayInt *conn, DataArrayInt *connIndex, bool isComputingTypes)
3253 DataArrayInt::SetArrayIn(conn,_nodal_connec);
3254 DataArrayInt::SetArrayIn(connIndex,_nodal_connec_index);
3255 if(isComputingTypes)
3261 * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3262 * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3264 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCopy):MEDCouplingPointSet(other,deepCopy),_mesh_dim(other._mesh_dim),
3265 _nodal_connec(0),_nodal_connec_index(0),
3266 _types(other._types)
3268 if(other._nodal_connec)
3269 _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCopy);
3270 if(other._nodal_connec_index)
3271 _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCopy);
3274 MEDCouplingUMesh::~MEDCouplingUMesh()
3277 _nodal_connec->decrRef();
3278 if(_nodal_connec_index)
3279 _nodal_connec_index->decrRef();
3283 * Recomputes a set of cell types of \a this mesh. For more info see
3284 * \ref MEDCouplingUMeshNodalConnectivity.
3286 void MEDCouplingUMesh::computeTypes()
3288 ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3292 * This method checks that all arrays are set. If yes nothing done if no an exception is thrown.
3294 void MEDCouplingUMesh::checkFullyDefined() const
3296 if(!_nodal_connec_index || !_nodal_connec || !_coords)
3297 throw INTERP_KERNEL::Exception("Reverse nodal connectivity computation requires full connectivity and coordinates set in unstructured mesh.");
3301 * This method checks that all connectivity arrays are set. If yes nothing done if no an exception is thrown.
3303 void MEDCouplingUMesh::checkConnectivityFullyDefined() const
3305 if(!_nodal_connec_index || !_nodal_connec)
3306 throw INTERP_KERNEL::Exception("Reverse nodal connectivity computation requires full connectivity set in unstructured mesh.");
3310 * Returns a number of cells constituting \a this mesh.
3311 * \return int - the number of cells in \a this mesh.
3312 * \throw If the nodal connectivity of cells is not defined.
3314 int MEDCouplingUMesh::getNumberOfCells() const
3316 if(_nodal_connec_index)
3317 return _nodal_connec_index->getNumberOfTuples()-1;
3322 throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3326 * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3327 * mesh. For more info see \ref meshes.
3328 * \return int - the dimension of \a this mesh.
3329 * \throw If the mesh dimension is not defined using setMeshDimension().
3331 int MEDCouplingUMesh::getMeshDimension() const
3334 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3339 * Returns a length of the nodal connectivity array.
3340 * This method is for test reason. Normally the integer returned is not useable by
3341 * user. For more info see \ref MEDCouplingUMeshNodalConnectivity.
3342 * \return int - the length of the nodal connectivity array.
3344 int MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3346 return _nodal_connec->getNbOfElems();
3350 * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3352 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<int>& tinyInfo, std::vector<std::string>& littleStrings) const
3354 MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3355 tinyInfo.push_back(getMeshDimension());
3356 tinyInfo.push_back(getNumberOfCells());
3358 tinyInfo.push_back(getNodalConnectivityArrayLen());
3360 tinyInfo.push_back(-1);
3364 * First step of unserialization process.
3366 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<int>& tinyInfo) const
3368 return tinyInfo[6]<=0;
3372 * Second step of serialization process.
3373 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3376 * \param littleStrings
3378 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<int>& tinyInfo, DataArrayInt *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3380 MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3382 a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3386 * Third and final step of serialization process.
3388 void MEDCouplingUMesh::serialize(DataArrayInt *&a1, DataArrayDouble *&a2) const
3390 MEDCouplingPointSet::serialize(a1,a2);
3391 if(getMeshDimension()>-1)
3393 a1=DataArrayInt::New();
3394 a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3395 int *ptA1=a1->getPointer();
3396 const int *conn=getNodalConnectivity()->getConstPointer();
3397 const int *index=getNodalConnectivityIndex()->getConstPointer();
3398 ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3399 std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3406 * Second and final unserialization process.
3407 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3409 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<int>& tinyInfo, const DataArrayInt *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3411 MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3412 setMeshDimension(tinyInfo[5]);
3416 const int *recvBuffer=a1->getConstPointer();
3417 MCAuto<DataArrayInt> myConnecIndex=DataArrayInt::New();
3418 myConnecIndex->alloc(tinyInfo[6]+1,1);
3419 std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3420 MCAuto<DataArrayInt> myConnec=DataArrayInt::New();
3421 myConnec->alloc(tinyInfo[7],1);
3422 std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3423 setConnectivity(myConnec, myConnecIndex);
3428 * This is the low algorithm of MEDCouplingUMesh::buildPartOfMySelfSlice.
3429 * CellIds are given using range specified by a start an end and step.
3431 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice(int start, int end, int step) const
3433 checkFullyDefined();
3434 int ncell=getNumberOfCells();
3435 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New();
3436 ret->_mesh_dim=_mesh_dim;
3437 ret->setCoords(_coords);
3438 int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice : ");
3439 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(newNbOfCells+1,1);
3440 int *newConnIPtr=newConnI->getPointer(); *newConnIPtr=0;
3442 const int *conn=_nodal_connec->getConstPointer();
3443 const int *connIndex=_nodal_connec_index->getConstPointer();
3444 for(int i=0;i<newNbOfCells;i++,newConnIPtr++,work+=step)
3446 if(work>=0 && work<ncell)
3448 newConnIPtr[1]=newConnIPtr[0]+connIndex[work+1]-connIndex[work];
3452 std::ostringstream oss; oss << "MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice : On pos #" << i << " input cell id =" << work << " should be in [0," << ncell << ") !";
3453 throw INTERP_KERNEL::Exception(oss.str());
3456 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(newConnIPtr[0],1);
3457 int *newConnPtr=newConn->getPointer();
3458 std::set<INTERP_KERNEL::NormalizedCellType> types;
3460 for(int i=0;i<newNbOfCells;i++,newConnIPtr++,work+=step)
3462 types.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[work]]);
3463 newConnPtr=std::copy(conn+connIndex[work],conn+connIndex[work+1],newConnPtr);
3465 ret->setConnectivity(newConn,newConnI,false);
3467 ret->copyTinyInfoFrom(this);
3472 * This is the low algorithm of MEDCouplingUMesh::buildPartOfMySelf.
3473 * Keeps from \a this only cells which constituing point id are in the ids specified by [ \a begin,\a end ).
3474 * The return newly allocated mesh will share the same coordinates as \a this.
3476 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfKeepCoords(const int *begin, const int *end) const
3478 checkConnectivityFullyDefined();
3479 int ncell=getNumberOfCells();
3480 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New();
3481 ret->_mesh_dim=_mesh_dim;
3482 ret->setCoords(_coords);
3483 std::size_t nbOfElemsRet=std::distance(begin,end);
3484 int *connIndexRet=(int *)malloc((nbOfElemsRet+1)*sizeof(int));
3486 const int *conn=_nodal_connec->getConstPointer();
3487 const int *connIndex=_nodal_connec_index->getConstPointer();
3489 for(const int *work=begin;work!=end;work++,newNbring++)
3491 if(*work>=0 && *work<ncell)
3492 connIndexRet[newNbring+1]=connIndexRet[newNbring]+connIndex[*work+1]-connIndex[*work];
3496 std::ostringstream oss; oss << "MEDCouplingUMesh::buildPartOfMySelfKeepCoords : On pos #" << std::distance(begin,work) << " input cell id =" << *work << " should be in [0," << ncell << ") !";
3497 throw INTERP_KERNEL::Exception(oss.str());
3500 int *connRet=(int *)malloc(connIndexRet[nbOfElemsRet]*sizeof(int));
3501 int *connRetWork=connRet;
3502 std::set<INTERP_KERNEL::NormalizedCellType> types;
3503 for(const int *work=begin;work!=end;work++)
3505 types.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*work]]);
3506 connRetWork=std::copy(conn+connIndex[*work],conn+connIndex[*work+1],connRetWork);
3508 MCAuto<DataArrayInt> connRetArr=DataArrayInt::New();
3509 connRetArr->useArray(connRet,true,C_DEALLOC,connIndexRet[nbOfElemsRet],1);
3510 MCAuto<DataArrayInt> connIndexRetArr=DataArrayInt::New();
3511 connIndexRetArr->useArray(connIndexRet,true,C_DEALLOC,(int)nbOfElemsRet+1,1);
3512 ret->setConnectivity(connRetArr,connIndexRetArr,false);
3514 ret->copyTinyInfoFrom(this);
3519 * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3521 * For 1D cells, the returned field contains lengths.<br>
3522 * For 2D cells, the returned field contains areas.<br>
3523 * For 3D cells, the returned field contains volumes.
3524 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3525 * orientation, i.e. the volume is always positive.
3526 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3527 * and one time . The caller is to delete this field using decrRef() as it is no
3530 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3532 std::string name="MeasureOfMesh_";
3534 int nbelem=getNumberOfCells();
3535 MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3536 field->setName(name);
3537 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3538 array->alloc(nbelem,1);
3539 double *area_vol=array->getPointer();
3540 field->setArray(array) ; array=0;
3541 field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3542 field->synchronizeTimeWithMesh();
3543 if(getMeshDimension()!=-1)
3546 INTERP_KERNEL::NormalizedCellType type;
3547 int dim_space=getSpaceDimension();
3548 const double *coords=getCoords()->getConstPointer();
3549 const int *connec=getNodalConnectivity()->getConstPointer();
3550 const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3551 for(int iel=0;iel<nbelem;iel++)
3553 ipt=connec_index[iel];
3554 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3555 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);
3558 std::transform(area_vol,area_vol+nbelem,area_vol,std::ptr_fun<double,double>(fabs));
3562 area_vol[0]=std::numeric_limits<double>::max();
3564 return field.retn();
3568 * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3570 * For 1D cells, the returned array contains lengths.<br>
3571 * For 2D cells, the returned array contains areas.<br>
3572 * For 3D cells, the returned array contains volumes.
3573 * This method avoids building explicitly a part of \a this mesh to perform the work.
3574 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3575 * orientation, i.e. the volume is always positive.
3576 * \param [in] begin - an array of cell ids of interest.
3577 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3578 * \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3579 * delete this array using decrRef() as it is no more needed.
3581 * \if ENABLE_EXAMPLES
3582 * \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3583 * \ref py_mcumesh_getPartMeasureField "Here is a Python example".
3585 * \sa getMeasureField()
3587 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const int *begin, const int *end) const
3589 std::string name="PartMeasureOfMesh_";
3591 int nbelem=(int)std::distance(begin,end);
3592 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3593 array->setName(name);
3594 array->alloc(nbelem,1);
3595 double *area_vol=array->getPointer();
3596 if(getMeshDimension()!=-1)
3599 INTERP_KERNEL::NormalizedCellType type;
3600 int dim_space=getSpaceDimension();
3601 const double *coords=getCoords()->getConstPointer();
3602 const int *connec=getNodalConnectivity()->getConstPointer();
3603 const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3604 for(const int *iel=begin;iel!=end;iel++)
3606 ipt=connec_index[*iel];
3607 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3608 *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<int,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3611 std::transform(array->getPointer(),area_vol,array->getPointer(),std::ptr_fun<double,double>(fabs));
3615 area_vol[0]=std::numeric_limits<double>::max();
3617 return array.retn();
3621 * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3622 * \a this one. The returned field contains the dual cell volume for each corresponding
3623 * node in \a this mesh. In other words, the field returns the getMeasureField() of
3624 * the dual mesh in P1 sens of \a this.<br>
3625 * For 1D cells, the returned field contains lengths.<br>
3626 * For 2D cells, the returned field contains areas.<br>
3627 * For 3D cells, the returned field contains volumes.
3628 * This method is useful to check "P1*" conservative interpolators.
3629 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3630 * orientation, i.e. the volume is always positive.
3631 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3632 * nodes and one time. The caller is to delete this array using decrRef() as
3633 * it is no more needed.
3635 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3637 MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3638 std::string name="MeasureOnNodeOfMesh_";
3640 int nbNodes=getNumberOfNodes();
3641 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3642 double cst=1./((double)getMeshDimension()+1.);
3643 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3644 array->alloc(nbNodes,1);
3645 double *valsToFill=array->getPointer();
3646 std::fill(valsToFill,valsToFill+nbNodes,0.);
3647 const double *values=tmp->getArray()->getConstPointer();
3648 MCAuto<DataArrayInt> da=DataArrayInt::New();
3649 MCAuto<DataArrayInt> daInd=DataArrayInt::New();
3650 getReverseNodalConnectivity(da,daInd);
3651 const int *daPtr=da->getConstPointer();
3652 const int *daIPtr=daInd->getConstPointer();
3653 for(int i=0;i<nbNodes;i++)
3654 for(const int *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3655 valsToFill[i]+=cst*values[*cell];
3657 ret->setArray(array);
3662 * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3663 * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3664 * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3665 * and are normalized.
3666 * <br> \a this can be either
3667 * - a 2D mesh in 2D or 3D space or
3668 * - an 1D mesh in 2D space.
3670 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3671 * cells and one time. The caller is to delete this field using decrRef() as
3672 * it is no more needed.
3673 * \throw If the nodal connectivity of cells is not defined.
3674 * \throw If the coordinates array is not set.
3675 * \throw If the mesh dimension is not set.
3676 * \throw If the mesh and space dimension is not as specified above.
3678 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3680 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3681 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3682 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3683 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3684 int nbOfCells=getNumberOfCells();
3685 int nbComp=getMeshDimension()+1;
3686 array->alloc(nbOfCells,nbComp);
3687 double *vals=array->getPointer();
3688 const int *connI=_nodal_connec_index->getConstPointer();
3689 const int *conn=_nodal_connec->getConstPointer();
3690 const double *coords=_coords->getConstPointer();
3691 if(getMeshDimension()==2)
3693 if(getSpaceDimension()==3)
3695 MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3696 const double *locPtr=loc->getConstPointer();
3697 for(int i=0;i<nbOfCells;i++,vals+=3)
3699 int offset=connI[i];
3700 INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3701 double n=INTERP_KERNEL::norm<3>(vals);
3702 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3707 MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3708 const double *isAbsPtr=isAbs->getArray()->begin();
3709 for(int i=0;i<nbOfCells;i++,isAbsPtr++)
3710 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3713 else//meshdimension==1
3716 for(int i=0;i<nbOfCells;i++)
3718 int offset=connI[i];
3719 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3720 double n=INTERP_KERNEL::norm<2>(tmp);
3721 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3726 ret->setArray(array);
3728 ret->synchronizeTimeWithSupport();
3733 * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3734 * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3735 * and are normalized.
3736 * <br> \a this can be either
3737 * - a 2D mesh in 2D or 3D space or
3738 * - an 1D mesh in 2D space.
3740 * This method avoids building explicitly a part of \a this mesh to perform the work.
3741 * \param [in] begin - an array of cell ids of interest.
3742 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3743 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3744 * cells and one time. The caller is to delete this field using decrRef() as
3745 * it is no more needed.
3746 * \throw If the nodal connectivity of cells is not defined.
3747 * \throw If the coordinates array is not set.
3748 * \throw If the mesh dimension is not set.
3749 * \throw If the mesh and space dimension is not as specified above.
3750 * \sa buildOrthogonalField()
3752 * \if ENABLE_EXAMPLES
3753 * \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3754 * \ref py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3757 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const int *begin, const int *end) const
3759 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3760 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3761 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3762 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3763 std::size_t nbelems=std::distance(begin,end);
3764 int nbComp=getMeshDimension()+1;
3765 array->alloc((int)nbelems,nbComp);
3766 double *vals=array->getPointer();
3767 const int *connI=_nodal_connec_index->getConstPointer();
3768 const int *conn=_nodal_connec->getConstPointer();
3769 const double *coords=_coords->getConstPointer();
3770 if(getMeshDimension()==2)
3772 if(getSpaceDimension()==3)
3774 MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3775 const double *locPtr=loc->getConstPointer();
3776 for(const int *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3778 int offset=connI[*i];
3779 INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3780 double n=INTERP_KERNEL::norm<3>(vals);
3781 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3786 for(std::size_t i=0;i<nbelems;i++)
3787 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3790 else//meshdimension==1
3793 for(const int *i=begin;i!=end;i++)
3795 int offset=connI[*i];
3796 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3797 double n=INTERP_KERNEL::norm<2>(tmp);
3798 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3803 ret->setArray(array);
3805 ret->synchronizeTimeWithSupport();
3810 * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3811 * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3812 * and are \b not normalized.
3813 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3814 * cells and one time. The caller is to delete this field using decrRef() as
3815 * it is no more needed.
3816 * \throw If the nodal connectivity of cells is not defined.
3817 * \throw If the coordinates array is not set.
3818 * \throw If \a this->getMeshDimension() != 1.
3819 * \throw If \a this mesh includes cells of type other than SEG2.
3821 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3823 if(getMeshDimension()!=1)
3824 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3825 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3826 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3827 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3828 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3829 int nbOfCells=getNumberOfCells();
3830 int spaceDim=getSpaceDimension();
3831 array->alloc(nbOfCells,spaceDim);
3832 double *pt=array->getPointer();
3833 const double *coo=getCoords()->getConstPointer();
3834 std::vector<int> conn;
3836 for(int i=0;i<nbOfCells;i++)
3839 getNodeIdsOfCell(i,conn);
3840 pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3842 ret->setArray(array);
3844 ret->synchronizeTimeWithSupport();
3849 * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3850 * returns a new DataArrayInt, of length equal to the number of 2D cells in the result
3851 * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3852 * from. If a result face is shared by two 3D cells, then the face in included twice in
3854 * \param [in] origin - 3 components of a point defining location of the plane.
3855 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3856 * must be greater than 1e-6.
3857 * \param [in] eps - half-thickness of the plane.
3858 * \param [out] cellIds - a new instance of DataArrayInt holding ids of 3D cells
3859 * producing correspondent 2D cells. The caller is to delete this array
3860 * using decrRef() as it is no more needed.
3861 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3862 * not share the node coordinates array with \a this mesh. The caller is to
3863 * delete this mesh using decrRef() as it is no more needed.
3864 * \throw If the coordinates array is not set.
3865 * \throw If the nodal connectivity of cells is not defined.
3866 * \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3867 * \throw If magnitude of \a vec is less than 1e-6.
3868 * \throw If the plane does not intersect any 3D cell of \a this mesh.
3869 * \throw If \a this includes quadratic cells.
3871 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3873 checkFullyDefined();
3874 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3875 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3876 MCAuto<DataArrayInt> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3877 if(candidates->empty())
3878 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3879 std::vector<int> nodes;
3880 DataArrayInt *cellIds1D=0;
3881 MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3882 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3883 MCAuto<DataArrayInt> desc1=DataArrayInt::New(),desc2=DataArrayInt::New();
3884 MCAuto<DataArrayInt> descIndx1=DataArrayInt::New(),descIndx2=DataArrayInt::New();
3885 MCAuto<DataArrayInt> revDesc1=DataArrayInt::New(),revDesc2=DataArrayInt::New();
3886 MCAuto<DataArrayInt> revDescIndx1=DataArrayInt::New(),revDescIndx2=DataArrayInt::New();
3887 MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3888 revDesc2=0; revDescIndx2=0;
3889 MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3890 revDesc1=0; revDescIndx1=0;
3891 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3892 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3894 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3895 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3897 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3898 std::vector< std::pair<int,int> > cut3DSurf(mDesc2->getNumberOfCells());
3899 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3900 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3901 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3902 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New());
3903 connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3904 subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3905 if(cellIds2->empty())
3906 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3907 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3908 ret->setCoords(mDesc1->getCoords());
3909 ret->setConnectivity(conn,connI,true);
3910 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3915 * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3916 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
3917 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3919 * \param [in] origin - 3 components of a point defining location of the plane.
3920 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3921 * must be greater than 1e-6.
3922 * \param [in] eps - half-thickness of the plane.
3923 * \param [out] cellIds - a new instance of DataArrayInt holding ids of faces
3924 * producing correspondent segments. The caller is to delete this array
3925 * using decrRef() as it is no more needed.
3926 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3927 * mesh in 3D space. This mesh does not share the node coordinates array with
3928 * \a this mesh. The caller is to delete this mesh using decrRef() as it is
3930 * \throw If the coordinates array is not set.
3931 * \throw If the nodal connectivity of cells is not defined.
3932 * \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3933 * \throw If magnitude of \a vec is less than 1e-6.
3934 * \throw If the plane does not intersect any 2D cell of \a this mesh.
3935 * \throw If \a this includes quadratic cells.
3937 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3939 checkFullyDefined();
3940 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3941 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3942 MCAuto<DataArrayInt> candidates(getCellIdsCrossingPlane(origin,vec,eps));
3943 if(candidates->empty())
3944 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3945 std::vector<int> nodes;
3946 DataArrayInt *cellIds1D(0);
3947 MCAuto<MEDCouplingUMesh> subMesh(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3948 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3949 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
3950 MCAuto<MEDCouplingUMesh> mDesc1(subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3951 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3952 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3954 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3955 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3957 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3958 int ncellsSub=subMesh->getNumberOfCells();
3959 std::vector< std::pair<int,int> > cut3DSurf(ncellsSub);
3960 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3961 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3962 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3963 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New()); connI->pushBackSilent(0);
3965 const int *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3966 const int *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3967 for(int i=0;i<ncellsSub;i++)
3969 if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3971 if(cut3DSurf[i].first!=-2)
3973 conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3974 connI->pushBackSilent(conn->getNumberOfTuples());
3975 cellIds2->pushBackSilent(i);
3979 int cellId3DSurf=cut3DSurf[i].second;
3980 int offset=nodalI[cellId3DSurf]+1;
3981 int nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3982 for(int j=0;j<nbOfEdges;j++)
3984 conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3985 connI->pushBackSilent(conn->getNumberOfTuples());
3986 cellIds2->pushBackSilent(cellId3DSurf);
3991 if(cellIds2->empty())
3992 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3993 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3994 ret->setCoords(mDesc1->getCoords());
3995 ret->setConnectivity(conn,connI,true);
3996 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
4000 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::clipSingle3DCellByPlane(const double origin[3], const double vec[3], double eps) const
4002 checkFullyDefined();
4003 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4004 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
4005 if(getNumberOfCells()!=1)
4006 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works only on mesh containing exactly one cell !");
4008 std::vector<int> nodes;
4009 findNodesOnPlane(origin,vec,eps,nodes);
4010 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),desc2(DataArrayInt::New()),descIndx1(DataArrayInt::New()),descIndx2(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDesc2(DataArrayInt::New()),revDescIndx1(DataArrayInt::New()),revDescIndx2(DataArrayInt::New());
4011 MCAuto<MEDCouplingUMesh> mDesc2(buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2));//meshDim==2 spaceDim==3
4012 revDesc2=0; revDescIndx2=0;
4013 MCAuto<MEDCouplingUMesh> mDesc1(mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
4014 revDesc1=0; revDescIndx1=0;
4015 DataArrayInt *cellIds1D(0);
4016 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
4017 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
4018 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
4019 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
4021 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
4022 std::vector< std::pair<int,int> > cut3DSurf(mDesc2->getNumberOfCells());
4023 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->begin(),mDesc2->getNodalConnectivityIndex()->begin(),
4024 mDesc1->getNodalConnectivity()->begin(),mDesc1->getNodalConnectivityIndex()->begin(),
4025 desc1->begin(),descIndx1->begin(),cut3DSurf);
4026 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New());
4027 connI->pushBackSilent(0); conn->alloc(0,1);
4029 MCAuto<DataArrayInt> cellIds2(DataArrayInt::New()); cellIds2->alloc(0,1);
4030 assemblyForSplitFrom3DSurf(cut3DSurf,desc2->begin(),descIndx2->begin(),conn,connI,cellIds2);
4031 if(cellIds2->empty())
4032 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
4034 std::vector<std::vector<int> > res;
4035 buildSubCellsFromCut(cut3DSurf,desc2->begin(),descIndx2->begin(),mDesc1->getCoords()->begin(),eps,res);
4036 std::size_t sz(res.size());
4037 if(res.size()==mDesc1->getNumberOfCells())
4038 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane : cell is not clipped !");
4039 for(std::size_t i=0;i<sz;i++)
4041 conn->pushBackSilent((int)INTERP_KERNEL::NORM_POLYGON);
4042 conn->insertAtTheEnd(res[i].begin(),res[i].end());
4043 connI->pushBackSilent(conn->getNumberOfTuples());
4045 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
4046 ret->setCoords(mDesc1->getCoords());
4047 ret->setConnectivity(conn,connI,true);
4048 int nbCellsRet(ret->getNumberOfCells());
4050 MCAuto<DataArrayDouble> vec2(DataArrayDouble::New()); vec2->alloc(1,3); std::copy(vec,vec+3,vec2->getPointer());
4051 MCAuto<MEDCouplingFieldDouble> ortho(ret->buildOrthogonalField());
4052 MCAuto<DataArrayDouble> ortho2(ortho->getArray()->selectByTupleIdSafeSlice(0,1,1));
4053 MCAuto<DataArrayDouble> dott(DataArrayDouble::Dot(ortho2,vec2));
4054 MCAuto<DataArrayDouble> ccm(ret->computeCellCenterOfMass());
4055 MCAuto<DataArrayDouble> occm;
4057 MCAuto<DataArrayDouble> pt(DataArrayDouble::New()); pt->alloc(1,3); std::copy(origin,origin+3,pt->getPointer());
4058 occm=DataArrayDouble::Substract(ccm,pt);
4060 vec2=DataArrayDouble::New(); vec2->alloc(nbCellsRet,3);
4061 vec2->setPartOfValuesSimple1(vec[0],0,nbCellsRet,1,0,1,1); vec2->setPartOfValuesSimple1(vec[1],0,nbCellsRet,1,1,2,1); vec2->setPartOfValuesSimple1(vec[2],0,nbCellsRet,1,2,3,1);
4062 MCAuto<DataArrayDouble> dott2(DataArrayDouble::Dot(occm,vec2));
4064 const int *cPtr(ret->getNodalConnectivity()->begin()),*ciPtr(ret->getNodalConnectivityIndex()->begin());
4065 MCAuto<MEDCouplingUMesh> ret2(MEDCouplingUMesh::New("Clip3D",3));
4066 ret2->setCoords(mDesc1->getCoords());
4067 MCAuto<DataArrayInt> conn2(DataArrayInt::New()),conn2I(DataArrayInt::New());
4068 conn2I->pushBackSilent(0); conn2->alloc(0,1);
4069 std::vector<int> cell0(1,(int)INTERP_KERNEL::NORM_POLYHED);
4070 std::vector<int> cell1(1,(int)INTERP_KERNEL::NORM_POLYHED);
4071 if(dott->getIJ(0,0)>0)
4073 cell0.insert(cell0.end(),cPtr+1,cPtr+ciPtr[1]);
4074 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell1,cell1.end()));
4078 cell1.insert(cell1.end(),cPtr+1,cPtr+ciPtr[1]);
4079 std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell0,cell0.end()));
4081 for(int i=1;i<nbCellsRet;i++)
4083 if(dott2->getIJ(i,0)<0)
4085 if(ciPtr[i+1]-ciPtr[i]>=4)
4087 cell0.push_back(-1);
4088 cell0.insert(cell0.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
4093 if(ciPtr[i+1]-ciPtr[i]>=4)
4095 cell1.push_back(-1);
4096 cell1.insert(cell1.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
4100 conn2->insertAtTheEnd(cell0.begin(),cell0.end());
4101 conn2I->pushBackSilent(conn2->getNumberOfTuples());
4102 conn2->insertAtTheEnd(cell1.begin(),cell1.end());
4103 conn2I->pushBackSilent(conn2->getNumberOfTuples());
4104 ret2->setConnectivity(conn2,conn2I,true);
4105 ret2->checkConsistencyLight();
4106 ret2->writeVTK("ret2.vtu");
4107 ret2->orientCorrectlyPolyhedrons();
4112 * Finds cells whose bounding boxes intersect a given plane.
4113 * \param [in] origin - 3 components of a point defining location of the plane.
4114 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
4115 * must be greater than 1e-6.
4116 * \param [in] eps - half-thickness of the plane.
4117 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of the found
4118 * cells. The caller is to delete this array using decrRef() as it is no more
4120 * \throw If the coordinates array is not set.
4121 * \throw If the nodal connectivity of cells is not defined.
4122 * \throw If \a this->getSpaceDimension() != 3.
4123 * \throw If magnitude of \a vec is less than 1e-6.
4124 * \sa buildSlice3D()
4126 DataArrayInt *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
4128 checkFullyDefined();
4129 if(getSpaceDimension()!=3)
4130 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
4131 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
4133 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
4135 vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
4136 double angle=acos(vec[2]/normm);
4137 MCAuto<DataArrayInt> cellIds;
4141 MCAuto<DataArrayDouble> coo=_coords->deepCopy();
4142 double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
4143 if(normm2/normm>1e-6)
4144 DataArrayDouble::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer(),coo->getPointer());
4145 MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
4147 mw->getBoundingBox(bbox);
4148 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
4149 cellIds=mw->getCellsInBoundingBox(bbox,eps);
4153 getBoundingBox(bbox);
4154 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
4155 cellIds=getCellsInBoundingBox(bbox,eps);
4157 return cellIds.retn();
4161 * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
4162 * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
4163 * No consideration of coordinate is done by this method.
4164 * 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)
4165 * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be usefull.
4167 bool MEDCouplingUMesh::isContiguous1D() const
4169 if(getMeshDimension()!=1)
4170 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
4171 int nbCells=getNumberOfCells();
4173 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
4174 const int *connI(_nodal_connec_index->begin()),*conn(_nodal_connec->begin());
4175 int ref=conn[connI[0]+2];
4176 for(int i=1;i<nbCells;i++)
4178 if(conn[connI[i]+1]!=ref)
4180 ref=conn[connI[i]+2];
4186 * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
4187 * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
4188 * \param pt reference point of the line
4189 * \param v normalized director vector of the line
4190 * \param eps max precision before throwing an exception
4191 * \param res output of size this->getNumberOfCells
4193 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
4195 if(getMeshDimension()!=1)
4196 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
4197 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
4198 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
4199 if(getSpaceDimension()!=3)
4200 throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
4201 MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
4202 const double *fPtr=f->getArray()->getConstPointer();
4204 for(int i=0;i<getNumberOfCells();i++)
4206 const double *tmp1=fPtr+3*i;
4207 tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
4208 tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
4209 tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
4210 double n1=INTERP_KERNEL::norm<3>(tmp);
4211 n1/=INTERP_KERNEL::norm<3>(tmp1);
4213 throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
4215 const double *coo=getCoords()->getConstPointer();
4216 for(int i=0;i<getNumberOfNodes();i++)
4218 std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
4219 std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
4220 res[i]=std::accumulate(tmp,tmp+3,0.);
4225 * 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.
4226 * \a this is expected to be a mesh so that its space dimension is equal to its
4227 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4228 * 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).
4230 * 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
4231 * 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).
4232 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4234 * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
4235 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4237 * \param [in] ptBg the start pointer (included) of the coordinates of the point
4238 * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
4239 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4240 * \return the positive value of the distance.
4241 * \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
4243 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
4245 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, int& cellId) const
4247 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4248 if(meshDim!=spaceDim-1)
4249 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
4250 if(meshDim!=2 && meshDim!=1)
4251 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
4252 checkFullyDefined();
4253 if((int)std::distance(ptBg,ptEnd)!=spaceDim)
4254 { 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()); }
4255 DataArrayInt *ret1=0;
4256 MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,C_DEALLOC,1,spaceDim);
4257 MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
4258 MCAuto<DataArrayInt> ret1Safe(ret1);
4259 cellId=*ret1Safe->begin();
4260 return *ret0->begin();
4264 * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
4265 * to \a this and the first \a cellId in \a this corresponding to the returned distance.
4266 * 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
4267 * 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).
4268 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4270 * \a this is expected to be a mesh so that its space dimension is equal to its
4271 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4272 * 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).
4274 * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
4275 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4277 * \param [in] pts the list of points in which each tuple represents a point
4278 * \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.
4279 * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
4280 * \throw if number of components of \a pts is not equal to the space dimension.
4281 * \throw if mesh dimension of \a this is not equal to space dimension - 1.
4282 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
4284 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayInt *& cellIds) const
4287 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
4288 pts->checkAllocated();
4289 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4290 if(meshDim!=spaceDim-1)
4291 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
4292 if(meshDim!=2 && meshDim!=1)
4293 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
4294 if(pts->getNumberOfComponents()!=spaceDim)
4296 std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
4297 throw INTERP_KERNEL::Exception(oss.str());
4299 checkFullyDefined();
4300 int nbCells=getNumberOfCells();
4302 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
4303 int nbOfPts=pts->getNumberOfTuples();
4304 MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
4305 MCAuto<DataArrayInt> ret1=DataArrayInt::New(); ret1->alloc(nbOfPts,1);
4306 const int *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
4307 double *ret0Ptr=ret0->getPointer(); int *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
4308 MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
4309 const double *bbox(bboxArr->begin());
4314 BBTreeDst<3> myTree(bbox,0,0,nbCells);
4315 for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
4317 double x=std::numeric_limits<double>::max();
4318 std::vector<int> elems;
4319 myTree.getMinDistanceOfMax(ptsPtr,x);
4320 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4321 DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4327 BBTreeDst<2> myTree(bbox,0,0,nbCells);
4328 for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4330 double x=std::numeric_limits<double>::max();
4331 std::vector<int> elems;
4332 myTree.getMinDistanceOfMax(ptsPtr,x);
4333 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4334 DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4339 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4341 cellIds=ret1.retn();
4348 * \param [in] pt the start pointer (included) of the coordinates of the point
4349 * \param [in] cellIdsBg the start pointer (included) of cellIds
4350 * \param [in] cellIdsEnd the end pointer (excluded) of cellIds
4351 * \param [in] nc nodal connectivity
4352 * \param [in] ncI nodal connectivity index
4353 * \param [in,out] ret0 the min distance between \a this and the external input point
4354 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4355 * \sa MEDCouplingUMesh::distanceToPoint, MEDCouplingUMesh::distanceToPoints
4357 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)
4360 ret0=std::numeric_limits<double>::max();
4361 for(const int *zeCell=cellIdsBg;zeCell!=cellIdsEnd;zeCell++)
4363 switch((INTERP_KERNEL::NormalizedCellType)nc[ncI[*zeCell]])
4365 case INTERP_KERNEL::NORM_TRI3:
4367 double tmp=INTERP_KERNEL::DistanceFromPtToTriInSpaceDim3(pt,coords+3*nc[ncI[*zeCell]+1],coords+3*nc[ncI[*zeCell]+2],coords+3*nc[ncI[*zeCell]+3]);
4369 { ret0=tmp; cellId=*zeCell; }
4372 case INTERP_KERNEL::NORM_QUAD4:
4373 case INTERP_KERNEL::NORM_POLYGON:
4375 double tmp=INTERP_KERNEL::DistanceFromPtToPolygonInSpaceDim3(pt,nc+ncI[*zeCell]+1,nc+ncI[*zeCell+1],coords);
4377 { ret0=tmp; cellId=*zeCell; }
4381 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint3DSurfAlg : not managed cell type ! Supporting TRI3, QUAD4 and POLYGON !");
4387 * \param [in] pt the start pointer (included) of the coordinates of the point
4388 * \param [in] cellIdsBg the start pointer (included) of cellIds
4389 * \param [in] cellIdsEnd the end pointer (excluded) of cellIds
4390 * \param [in] nc nodal connectivity
4391 * \param [in] ncI nodal connectivity index
4392 * \param [in,out] ret0 the min distance between \a this and the external input point
4393 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4394 * \sa MEDCouplingUMesh::distanceToPoint, MEDCouplingUMesh::distanceToPoints
4396 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)
4399 ret0=std::numeric_limits<double>::max();
4400 for(const int *zeCell=cellIdsBg;zeCell!=cellIdsEnd;zeCell++)
4402 switch((INTERP_KERNEL::NormalizedCellType)nc[ncI[*zeCell]])
4404 case INTERP_KERNEL::NORM_SEG2:
4406 std::size_t uselessEntry=0;
4407 double tmp=INTERP_KERNEL::SquareDistanceFromPtToSegInSpaceDim2(pt,coords+2*nc[ncI[*zeCell]+1],coords+2*nc[ncI[*zeCell]+2],uselessEntry);
4410 { ret0=tmp; cellId=*zeCell; }
4414 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint2DCurveAlg : not managed cell type ! Supporting SEG2 !");
4421 * Finds cells in contact with a ball (i.e. a point with precision).
4422 * 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.
4423 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4425 * \warning This method is suitable if the caller intends to evaluate only one
4426 * point, for more points getCellsContainingPoints() is recommended as it is
4428 * \param [in] pos - array of coordinates of the ball central point.
4429 * \param [in] eps - ball radius.
4430 * \return int - a smallest id of cells being in contact with the ball, -1 in case
4431 * if there are no such cells.
4432 * \throw If the coordinates array is not set.
4433 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4435 int MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4437 std::vector<int> elts;
4438 getCellsContainingPoint(pos,eps,elts);
4441 return elts.front();
4445 * Finds cells in contact with a ball (i.e. a point with precision).
4446 * 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.
4447 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4448 * \warning This method is suitable if the caller intends to evaluate only one
4449 * point, for more points getCellsContainingPoints() is recommended as it is
4451 * \param [in] pos - array of coordinates of the ball central point.
4452 * \param [in] eps - ball radius.
4453 * \param [out] elts - vector returning ids of the found cells. It is cleared
4454 * before inserting ids.
4455 * \throw If the coordinates array is not set.
4456 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4458 * \if ENABLE_EXAMPLES
4459 * \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4460 * \ref py_mcumesh_getCellsContainingPoint "Here is a Python example".
4463 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<int>& elts) const
4465 MCAuto<DataArrayInt> eltsUg,eltsIndexUg;
4466 getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4467 elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4472 namespace MEDCoupling
4474 template<const int SPACEDIMM>
4478 static const int MY_SPACEDIM=SPACEDIMM;
4479 static const int MY_MESHDIM=8;
4480 typedef int MyConnType;
4481 static const INTERP_KERNEL::NumberingPolicy My_numPol=INTERP_KERNEL::ALL_C_MODE;
4483 // useless, but for windows compilation ...
4484 const double* getCoordinatesPtr() const { return 0; }
4485 const int* getConnectivityPtr() const { return 0; }
4486 const int* getConnectivityIndexPtr() const { return 0; }
4487 INTERP_KERNEL::NormalizedCellType getTypeOfElement(int) const { return (INTERP_KERNEL::NormalizedCellType)0; }
4491 INTERP_KERNEL::Edge *MEDCouplingUMeshBuildQPFromEdge2(INTERP_KERNEL::NormalizedCellType typ, const int *bg, const double *coords2D, std::map< MCAuto<INTERP_KERNEL::Node>,int>& m)
4493 INTERP_KERNEL::Edge *ret(0);
4494 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]));
4495 m[n0]=bg[0]; m[n1]=bg[1];
4498 case INTERP_KERNEL::NORM_SEG2:
4500 ret=new INTERP_KERNEL::EdgeLin(n0,n1);
4503 case INTERP_KERNEL::NORM_SEG3:
4505 INTERP_KERNEL::Node *n2(new INTERP_KERNEL::Node(coords2D[2*bg[2]],coords2D[2*bg[2]+1])); m[n2]=bg[2];
4506 INTERP_KERNEL::EdgeLin *e1(new INTERP_KERNEL::EdgeLin(n0,n2)),*e2(new INTERP_KERNEL::EdgeLin(n2,n1));
4507 INTERP_KERNEL::SegSegIntersector inters(*e1,*e2);
4508 // is the SEG3 degenerated, and thus can be reduced to a SEG2?
4509 bool colinearity(inters.areColinears());
4510 delete e1; delete e2;
4512 { ret=new INTERP_KERNEL::EdgeLin(n0,n1); }
4514 { ret=new INTERP_KERNEL::EdgeArcCircle(n0,n2,n1); }
4518 throw INTERP_KERNEL::Exception("MEDCouplingUMeshBuildQPFromEdge2 : Expecting a mesh with spaceDim==2 and meshDim==1 !");
4523 INTERP_KERNEL::Edge *MEDCouplingUMeshBuildQPFromEdge(INTERP_KERNEL::NormalizedCellType typ, std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >& mapp2, const int *bg)
4525 INTERP_KERNEL::Edge *ret=0;
4528 case INTERP_KERNEL::NORM_SEG2:
4530 ret=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[1]].first);
4533 case INTERP_KERNEL::NORM_SEG3:
4535 INTERP_KERNEL::EdgeLin *e1=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[2]].first);
4536 INTERP_KERNEL::EdgeLin *e2=new INTERP_KERNEL::EdgeLin(mapp2[bg[2]].first,mapp2[bg[1]].first);
4537 INTERP_KERNEL::SegSegIntersector inters(*e1,*e2);
4538 // is the SEG3 degenerated, and thus can be reduced to a SEG2?
4539 bool colinearity=inters.areColinears();
4540 delete e1; delete e2;
4542 ret=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[1]].first);
4544 ret=new INTERP_KERNEL::EdgeArcCircle(mapp2[bg[0]].first,mapp2[bg[2]].first,mapp2[bg[1]].first);
4545 mapp2[bg[2]].second=false;
4549 throw INTERP_KERNEL::Exception("MEDCouplingUMeshBuildQPFromEdge : Expecting a mesh with spaceDim==2 and meshDim==1 !");
4555 * This method creates a sub mesh in Geometric2D DS. The sub mesh is composed by the sub set of cells in 'candidates' taken from
4556 * the global mesh 'mDesc'.
4557 * The input mesh 'mDesc' must be so that mDim==1 and spaceDim==2.
4558 * 'mapp' returns a mapping between local numbering in submesh (represented by a Node*) and the global node numbering in 'mDesc'.
4560 INTERP_KERNEL::QuadraticPolygon *MEDCouplingUMeshBuildQPFromMesh(const MEDCouplingUMesh *mDesc, const std::vector<int>& candidates,
4561 std::map<INTERP_KERNEL::Node *,int>& mapp)
4564 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.
4565 const double *coo=mDesc->getCoords()->getConstPointer();
4566 const int *c=mDesc->getNodalConnectivity()->getConstPointer();
4567 const int *cI=mDesc->getNodalConnectivityIndex()->getConstPointer();
4569 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
4570 s.insert(c+cI[*it]+1,c+cI[(*it)+1]);
4571 for(std::set<int>::const_iterator it2=s.begin();it2!=s.end();it2++)
4573 INTERP_KERNEL::Node *n=new INTERP_KERNEL::Node(coo[2*(*it2)],coo[2*(*it2)+1]);
4574 mapp2[*it2]=std::pair<INTERP_KERNEL::Node *,bool>(n,true);
4576 INTERP_KERNEL::QuadraticPolygon *ret=new INTERP_KERNEL::QuadraticPolygon;
4577 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
4579 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[*it]];
4580 ret->pushBack(MEDCouplingUMeshBuildQPFromEdge(typ,mapp2,c+cI[*it]+1));
4582 for(std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >::const_iterator it2=mapp2.begin();it2!=mapp2.end();it2++)
4584 if((*it2).second.second)
4585 mapp[(*it2).second.first]=(*it2).first;
4586 ((*it2).second.first)->decrRef();
4591 INTERP_KERNEL::Node *MEDCouplingUMeshBuildQPNode(int nodeId, const double *coo1, int offset1, const double *coo2, int offset2, const std::vector<double>& addCoo)
4595 int locId=nodeId-offset2;
4596 return new INTERP_KERNEL::Node(addCoo[2*locId],addCoo[2*locId+1]);
4600 int locId=nodeId-offset1;
4601 return new INTERP_KERNEL::Node(coo2[2*locId],coo2[2*locId+1]);
4603 return new INTERP_KERNEL::Node(coo1[2*nodeId],coo1[2*nodeId+1]);
4607 * Construct a mapping between set of Nodes and the standart MEDCoupling connectivity format (c, cI).
4609 void MEDCouplingUMeshBuildQPFromMesh3(const double *coo1, int offset1, const double *coo2, int offset2, const std::vector<double>& addCoo,
4610 const int *desc1Bg, const int *desc1End, const std::vector<std::vector<int> >& intesctEdges1,
4611 /*output*/std::map<INTERP_KERNEL::Node *,int>& mapp, std::map<int,INTERP_KERNEL::Node *>& mappRev)
4613 for(const int *desc1=desc1Bg;desc1!=desc1End;desc1++)
4615 int eltId1=abs(*desc1)-1;
4616 for(std::vector<int>::const_iterator it1=intesctEdges1[eltId1].begin();it1!=intesctEdges1[eltId1].end();it1++)
4618 std::map<int,INTERP_KERNEL::Node *>::const_iterator it=mappRev.find(*it1);
4619 if(it==mappRev.end())
4621 INTERP_KERNEL::Node *node=MEDCouplingUMeshBuildQPNode(*it1,coo1,offset1,coo2,offset2,addCoo);
4632 template<int SPACEDIM>
4633 void MEDCouplingUMesh::getCellsContainingPointsAlg(const double *coords, const double *pos, int nbOfPoints,
4634 double eps, MCAuto<DataArrayInt>& elts, MCAuto<DataArrayInt>& eltsIndex) const
4636 elts=DataArrayInt::New(); eltsIndex=DataArrayInt::New(); eltsIndex->alloc(nbOfPoints+1,1); eltsIndex->setIJ(0,0,0); elts->alloc(0,1);
4637 int *eltsIndexPtr(eltsIndex->getPointer());
4638 MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree(eps));
4639 const double *bbox(bboxArr->begin());
4640 int nbOfCells=getNumberOfCells();
4641 const int *conn=_nodal_connec->getConstPointer();
4642 const int *connI=_nodal_connec_index->getConstPointer();
4643 double bb[2*SPACEDIM];
4644 BBTree<SPACEDIM,int> myTree(&bbox[0],0,0,nbOfCells,-eps);
4645 for(int i=0;i<nbOfPoints;i++)
4647 eltsIndexPtr[i+1]=eltsIndexPtr[i];
4648 for(int j=0;j<SPACEDIM;j++)
4650 bb[2*j]=pos[SPACEDIM*i+j];
4651 bb[2*j+1]=pos[SPACEDIM*i+j];
4653 std::vector<int> candidates;
4654 myTree.getIntersectingElems(bb,candidates);
4655 for(std::vector<int>::const_iterator iter=candidates.begin();iter!=candidates.end();iter++)
4657 int sz(connI[(*iter)+1]-connI[*iter]-1);
4658 INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[connI[*iter]]);
4660 if(ct!=INTERP_KERNEL::NORM_POLYGON && ct!=INTERP_KERNEL::NORM_QPOLYG)
4661 status=INTERP_KERNEL::PointLocatorAlgos<DummyClsMCUG<SPACEDIM> >::isElementContainsPoint(pos+i*SPACEDIM,ct,coords,conn+connI[*iter]+1,sz,eps);
4665 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPointsAlg : not implemented yet for POLYGON and QPOLYGON in spaceDim 3 !");
4666 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
4667 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
4668 std::vector<INTERP_KERNEL::Node *> nodes(sz);
4669 INTERP_KERNEL::QuadraticPolygon *pol(0);
4670 for(int j=0;j<sz;j++)
4672 int nodeId(conn[connI[*iter]+1+j]);
4673 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*SPACEDIM],coords[nodeId*SPACEDIM+1]);
4675 if(!INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic())
4676 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
4678 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
4679 INTERP_KERNEL::Node *n(new INTERP_KERNEL::Node(pos[i*SPACEDIM],pos[i*SPACEDIM+1]));
4680 double a(0.),b(0.),c(0.);
4681 a=pol->normalizeMe(b,c); n->applySimilarity(b,c,a);
4682 status=pol->isInOrOut2(n);
4683 delete pol; n->decrRef();
4687 eltsIndexPtr[i+1]++;
4688 elts->pushBackSilent(*iter);
4694 * Finds cells in contact with several balls (i.e. points with precision).
4695 * This method is an extension of getCellContainingPoint() and
4696 * getCellsContainingPoint() for the case of multiple points.
4697 * 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.
4698 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4699 * \param [in] pos - an array of coordinates of points in full interlace mode :
4700 * X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4701 * this->getSpaceDimension() * \a nbOfPoints
4702 * \param [in] nbOfPoints - number of points to locate within \a this mesh.
4703 * \param [in] eps - radius of balls (i.e. the precision).
4704 * \param [out] elts - vector returning ids of found cells.
4705 * \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4706 * dividing cell ids in \a elts into groups each referring to one
4707 * point. Its every element (except the last one) is an index pointing to the
4708 * first id of a group of cells. For example cells in contact with the *i*-th
4709 * point are described by following range of indices:
4710 * [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4711 * \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4712 * Number of cells in contact with the *i*-th point is
4713 * \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4714 * \throw If the coordinates array is not set.
4715 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4717 * \if ENABLE_EXAMPLES
4718 * \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4719 * \ref py_mcumesh_getCellsContainingPoints "Here is a Python example".
4722 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, int nbOfPoints, double eps,
4723 MCAuto<DataArrayInt>& elts, MCAuto<DataArrayInt>& eltsIndex) const
4725 int spaceDim=getSpaceDimension();
4726 int mDim=getMeshDimension();
4731 const double *coords=_coords->getConstPointer();
4732 getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4739 throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4741 else if(spaceDim==2)
4745 const double *coords=_coords->getConstPointer();
4746 getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4749 throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4751 else if(spaceDim==1)
4755 const double *coords=_coords->getConstPointer();
4756 getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4759 throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4762 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4766 * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4767 * least two its edges intersect each other anywhere except their extremities. An
4768 * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4769 * \param [in,out] cells - a vector returning ids of the found cells. It is not
4770 * cleared before filling in.
4771 * \param [in] eps - precision.
4772 * \throw If \a this->getMeshDimension() != 2.
4773 * \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4775 void MEDCouplingUMesh::checkButterflyCells(std::vector<int>& cells, double eps) const
4777 const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4778 if(getMeshDimension()!=2)
4779 throw INTERP_KERNEL::Exception(msg);
4780 int spaceDim=getSpaceDimension();
4781 if(spaceDim!=2 && spaceDim!=3)
4782 throw INTERP_KERNEL::Exception(msg);
4783 const int *conn=_nodal_connec->getConstPointer();
4784 const int *connI=_nodal_connec_index->getConstPointer();
4785 int nbOfCells=getNumberOfCells();
4786 std::vector<double> cell2DinS2;
4787 for(int i=0;i<nbOfCells;i++)
4789 int offset=connI[i];
4790 int nbOfNodesForCell=connI[i+1]-offset-1;
4791 if(nbOfNodesForCell<=3)
4793 bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4794 project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4795 if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4802 * This method is typically requested to unbutterfly 2D linear cells in \b this.
4804 * 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.
4805 * 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.
4807 * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4808 * This convex envelop is computed using Jarvis march algorithm.
4809 * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4810 * 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)
4811 * 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.
4813 * \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.
4814 * \sa MEDCouplingUMesh::colinearize2D
4816 DataArrayInt *MEDCouplingUMesh::convexEnvelop2D()
4818 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4819 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D works only for meshDim=2 and spaceDim=2 !");
4820 checkFullyDefined();
4821 const double *coords=getCoords()->getConstPointer();
4822 int nbOfCells=getNumberOfCells();
4823 MCAuto<DataArrayInt> nodalConnecIndexOut=DataArrayInt::New();
4824 nodalConnecIndexOut->alloc(nbOfCells+1,1);
4825 MCAuto<DataArrayInt> nodalConnecOut(DataArrayInt::New());
4826 int *workIndexOut=nodalConnecIndexOut->getPointer();
4828 const int *nodalConnecIn=_nodal_connec->getConstPointer();
4829 const int *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4830 std::set<INTERP_KERNEL::NormalizedCellType> types;
4831 MCAuto<DataArrayInt> isChanged(DataArrayInt::New());
4832 isChanged->alloc(0,1);
4833 for(int i=0;i<nbOfCells;i++,workIndexOut++)
4835 int pos=nodalConnecOut->getNumberOfTuples();
4836 if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4837 isChanged->pushBackSilent(i);
4838 types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4839 workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4841 if(isChanged->empty())
4843 setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4845 return isChanged.retn();
4849 * This method is \b NOT const because it can modify \a this.
4850 * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4851 * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4852 * \param policy specifies the type of extrusion chosen:
4853 * - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4854 * will be repeated to build each level
4855 * - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4856 * 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
4857 * 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
4859 * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4861 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4863 checkFullyDefined();
4864 mesh1D->checkFullyDefined();
4865 if(!mesh1D->isContiguous1D())
4866 throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4867 if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4868 throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4869 if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4870 throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4871 if(mesh1D->getMeshDimension()!=1)
4872 throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4874 if(isPresenceOfQuadratic())
4876 if(mesh1D->isFullyQuadratic())
4879 throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4881 int oldNbOfNodes(getNumberOfNodes());
4882 MCAuto<DataArrayDouble> newCoords;
4887 newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4892 newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4896 throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4898 setCoords(newCoords);
4899 MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4905 * This method works on a 3D curve linear mesh that is to say (meshDim==1 and spaceDim==3).
4906 * If it is not the case an exception will be thrown.
4907 * This method is non const because the coordinate of \a this can be appended with some new points issued from
4908 * intersection of plane defined by ('origin','vec').
4909 * This method has one in/out parameter : 'cut3DCurve'.
4910 * Param 'cut3DCurve' is expected to be of size 'this->getNumberOfCells()'. For each i in [0,'this->getNumberOfCells()')
4911 * if cut3DCurve[i]==-2, it means that for cell #i in \a this nothing has been detected previously.
4912 * if cut3DCurve[i]==-1, it means that cell#i has been already detected to be fully part of plane defined by ('origin','vec').
4913 * This method will throw an exception if \a this contains a non linear segment.
4915 void MEDCouplingUMesh::split3DCurveWithPlane(const double *origin, const double *vec, double eps, std::vector<int>& cut3DCurve)
4917 checkFullyDefined();
4918 if(getMeshDimension()!=1 || getSpaceDimension()!=3)
4919 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane works on umeshes with meshdim equal to 1 and spaceDim equal to 3 !");
4920 int ncells=getNumberOfCells();
4921 int nnodes=getNumberOfNodes();
4922 double vec2[3],vec3[3],vec4[3];
4923 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
4925 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
4926 vec2[0]=vec[0]/normm; vec2[1]=vec[1]/normm; vec2[2]=vec[2]/normm;
4927 const int *conn=_nodal_connec->getConstPointer();
4928 const int *connI=_nodal_connec_index->getConstPointer();
4929 const double *coo=_coords->getConstPointer();
4930 std::vector<double> addCoo;
4931 for(int i=0;i<ncells;i++)
4933 if(conn[connI[i]]==(int)INTERP_KERNEL::NORM_SEG2)
4935 if(cut3DCurve[i]==-2)
4937 int st=conn[connI[i]+1],endd=conn[connI[i]+2];
4938 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];
4939 double normm2=sqrt(vec3[0]*vec3[0]+vec3[1]*vec3[1]+vec3[2]*vec3[2]);
4940 double colin=std::abs((vec3[0]*vec2[0]+vec3[1]*vec2[1]+vec3[2]*vec2[2])/normm2);
4941 if(colin>eps)//if colin<=eps -> current SEG2 is colinear to the input plane
4943 const double *st2=coo+3*st;
4944 vec4[0]=st2[0]-origin[0]; vec4[1]=st2[1]-origin[1]; vec4[2]=st2[2]-origin[2];
4945 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]));
4946 if(pos>eps && pos<1-eps)
4948 int nNode=((int)addCoo.size())/3;
4949 vec4[0]=st2[0]+pos*vec3[0]; vec4[1]=st2[1]+pos*vec3[1]; vec4[2]=st2[2]+pos*vec3[2];
4950 addCoo.insert(addCoo.end(),vec4,vec4+3);
4951 cut3DCurve[i]=nnodes+nNode;
4957 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane : this method is only available for linear cell (NORM_SEG2) !");
4961 int newNbOfNodes=nnodes+((int)addCoo.size())/3;
4962 MCAuto<DataArrayDouble> coo2=DataArrayDouble::New();
4963 coo2->alloc(newNbOfNodes,3);
4964 double *tmp=coo2->getPointer();
4965 tmp=std::copy(_coords->begin(),_coords->end(),tmp);
4966 std::copy(addCoo.begin(),addCoo.end(),tmp);
4967 DataArrayDouble::SetArrayIn(coo2,_coords);
4972 * This method incarnates the policy 0 for MEDCouplingUMesh::buildExtrudedMesh method.
4973 * \param mesh1D is the input 1D mesh used for translation computation.
4974 * \return newCoords new coords filled by this method.
4976 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslation(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4978 int oldNbOfNodes=getNumberOfNodes();
4979 int nbOf1DCells=mesh1D->getNumberOfCells();
4980 int spaceDim=getSpaceDimension();
4981 DataArrayDouble *ret=DataArrayDouble::New();
4982 std::vector<bool> isQuads;
4983 int nbOfLevsInVec=isQuad?2*nbOf1DCells+1:nbOf1DCells+1;
4984 ret->alloc(oldNbOfNodes*nbOfLevsInVec,spaceDim);
4985 double *retPtr=ret->getPointer();
4986 const double *coords=getCoords()->getConstPointer();
4987 double *work=std::copy(coords,coords+spaceDim*oldNbOfNodes,retPtr);
4989 std::vector<double> c;
4993 for(int i=0;i<nbOf1DCells;i++)
4996 mesh1D->getNodeIdsOfCell(i,v);
4998 mesh1D->getCoordinatesOfNode(v[isQuad?2:1],c);
4999 mesh1D->getCoordinatesOfNode(v[0],c);
5000 std::transform(c.begin(),c.begin()+spaceDim,c.begin()+spaceDim,vec,std::minus<double>());
5001 for(int j=0;j<oldNbOfNodes;j++)
5002 work=std::transform(vec,vec+spaceDim,retPtr+spaceDim*(i*oldNbOfNodes+j),work,std::plus<double>());
5006 mesh1D->getCoordinatesOfNode(v[1],c);
5007 mesh1D->getCoordinatesOfNode(v[0],c);
5008 std::transform(c.begin(),c.begin()+spaceDim,c.begin()+spaceDim,vec,std::minus<double>());
5009 for(int j=0;j<oldNbOfNodes;j++)
5010 work=std::transform(vec,vec+spaceDim,retPtr+spaceDim*(i*oldNbOfNodes+j),work,std::plus<double>());
5013 ret->copyStringInfoFrom(*getCoords());
5018 * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
5019 * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
5020 * \return newCoords new coords filled by this method.
5022 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation(const MEDCouplingUMesh *mesh1D, bool isQuad) const
5024 if(mesh1D->getSpaceDimension()==2)
5025 return fillExtCoordsUsingTranslAndAutoRotation2D(mesh1D,isQuad);
5026 if(mesh1D->getSpaceDimension()==3)
5027 return fillExtCoordsUsingTranslAndAutoRotation3D(mesh1D,isQuad);
5028 throw INTERP_KERNEL::Exception("Not implemented rotation and translation alg. for spacedim other than 2 and 3 !");
5032 * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
5033 * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
5034 * \return newCoords new coords filled by this method.
5036 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D(const MEDCouplingUMesh *mesh1D, bool isQuad) const
5039 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D : not implemented for quadratic cells !");
5040 int oldNbOfNodes=getNumberOfNodes();
5041 int nbOf1DCells=mesh1D->getNumberOfCells();
5043 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D : impossible to detect any angle of rotation ! Change extrusion policy 1->0 !");
5044 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
5045 int nbOfLevsInVec=nbOf1DCells+1;
5046 ret->alloc(oldNbOfNodes*nbOfLevsInVec,2);
5047 double *retPtr=ret->getPointer();
5048 retPtr=std::copy(getCoords()->getConstPointer(),getCoords()->getConstPointer()+getCoords()->getNbOfElems(),retPtr);
5049 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
5050 MCAuto<DataArrayDouble> tmp2=getCoords()->deepCopy();
5051 tmp->setCoords(tmp2);
5052 const double *coo1D=mesh1D->getCoords()->getConstPointer();
5053 const int *conn1D=mesh1D->getNodalConnectivity()->getConstPointer();
5054 const int *connI1D=mesh1D->getNodalConnectivityIndex()->getConstPointer();
5055 for(int i=1;i<nbOfLevsInVec;i++)
5057 const double *begin=coo1D+2*conn1D[connI1D[i-1]+1];
5058 const double *end=coo1D+2*conn1D[connI1D[i-1]+2];
5059 const double *third=i+1<nbOfLevsInVec?coo1D+2*conn1D[connI1D[i]+2]:coo1D+2*conn1D[connI1D[i-2]+1];
5060 const double vec[2]={end[0]-begin[0],end[1]-begin[1]};
5061 tmp->translate(vec);
5062 double tmp3[2],radius,alpha,alpha0;
5063 const double *p0=i+1<nbOfLevsInVec?begin:third;
5064 const double *p1=i+1<nbOfLevsInVec?end:begin;
5065 const double *p2=i+1<nbOfLevsInVec?third:end;
5066 INTERP_KERNEL::EdgeArcCircle::GetArcOfCirclePassingThru(p0,p1,p2,tmp3,radius,alpha,alpha0);
5067 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]);
5068 double angle=acos(cosangle/(radius*radius));
5069 tmp->rotate(end,0,angle);
5070 retPtr=std::copy(tmp2->getConstPointer(),tmp2->getConstPointer()+tmp2->getNbOfElems(),retPtr);
5076 * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
5077 * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
5078 * \return newCoords new coords filled by this method.
5080 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D(const MEDCouplingUMesh *mesh1D, bool isQuad) const
5083 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D : not implemented for quadratic cells !");
5084 int oldNbOfNodes=getNumberOfNodes();
5085 int nbOf1DCells=mesh1D->getNumberOfCells();
5087 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D : impossible to detect any angle of rotation ! Change extrusion policy 1->0 !");
5088 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
5089 int nbOfLevsInVec=nbOf1DCells+1;
5090 ret->alloc(oldNbOfNodes*nbOfLevsInVec,3);
5091 double *retPtr=ret->getPointer();
5092 retPtr=std::copy(getCoords()->getConstPointer(),getCoords()->getConstPointer()+getCoords()->getNbOfElems(),retPtr);
5093 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
5094 MCAuto<DataArrayDouble> tmp2=getCoords()->deepCopy();
5095 tmp->setCoords(tmp2);
5096 const double *coo1D=mesh1D->getCoords()->getConstPointer();
5097 const int *conn1D=mesh1D->getNodalConnectivity()->getConstPointer();
5098 const int *connI1D=mesh1D->getNodalConnectivityIndex()->getConstPointer();
5099 for(int i=1;i<nbOfLevsInVec;i++)
5101 const double *begin=coo1D+3*conn1D[connI1D[i-1]+1];
5102 const double *end=coo1D+3*conn1D[connI1D[i-1]+2];
5103 const double *third=i+1<nbOfLevsInVec?coo1D+3*conn1D[connI1D[i]+2]:coo1D+3*conn1D[connI1D[i-2]+1];
5104 const double vec[3]={end[0]-begin[0],end[1]-begin[1],end[2]-begin[2]};
5105 tmp->translate(vec);
5106 double tmp3[2],radius,alpha,alpha0;
5107 const double *p0=i+1<nbOfLevsInVec?begin:third;
5108 const double *p1=i+1<nbOfLevsInVec?end:begin;
5109 const double *p2=i+1<nbOfLevsInVec?third:end;
5110 double vecPlane[3]={
5111 (p1[1]-p0[1])*(p2[2]-p1[2])-(p1[2]-p0[2])*(p2[1]-p1[1]),
5112 (p1[2]-p0[2])*(p2[0]-p1[0])-(p1[0]-p0[0])*(p2[2]-p1[2]),
5113 (p1[0]-p0[0])*(p2[1]-p1[1])-(p1[1]-p0[1])*(p2[0]-p1[0]),
5115 double norm=sqrt(vecPlane[0]*vecPlane[0]+vecPlane[1]*vecPlane[1]+vecPlane[2]*vecPlane[2]);
5118 vecPlane[0]/=norm; vecPlane[1]/=norm; vecPlane[2]/=norm;
5119 double norm2=sqrt(vecPlane[0]*vecPlane[0]+vecPlane[1]*vecPlane[1]);
5120 double vec2[2]={vecPlane[1]/norm2,-vecPlane[0]/norm2};
5122 double c2=cos(asin(s2));
5124 {vec2[0]*vec2[0]*(1-c2)+c2, vec2[0]*vec2[1]*(1-c2), vec2[1]*s2},
5125 {vec2[0]*vec2[1]*(1-c2), vec2[1]*vec2[1]*(1-c2)+c2, -vec2[0]*s2},
5126 {-vec2[1]*s2, vec2[0]*s2, c2}
5128 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]};
5129 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]};
5130 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]};
5131 INTERP_KERNEL::EdgeArcCircle::GetArcOfCirclePassingThru(p0r,p1r,p2r,tmp3,radius,alpha,alpha0);
5132 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]);
5133 double angle=acos(cosangle/(radius*radius));
5134 tmp->rotate(end,vecPlane,angle);
5136 retPtr=std::copy(tmp2->getConstPointer(),tmp2->getConstPointer()+tmp2->getNbOfElems(),retPtr);
5142 * This method is private because not easy to use for end user. This method is const contrary to
5143 * MEDCouplingUMesh::buildExtrudedMesh method because this->_coords are expected to contain
5144 * the coords sorted slice by slice.
5145 * \param isQuad specifies presence of quadratic cells.
5147 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMeshFromThisLowLev(int nbOfNodesOf1Lev, bool isQuad) const
5149 int nbOf1DCells(getNumberOfNodes()/nbOfNodesOf1Lev-1);
5150 int nbOf2DCells(getNumberOfCells());
5151 int nbOf3DCells(nbOf2DCells*nbOf1DCells);
5152 MEDCouplingUMesh *ret(MEDCouplingUMesh::New("Extruded",getMeshDimension()+1));
5153 const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5154 MCAuto<DataArrayInt> newConn(DataArrayInt::New()),newConnI(DataArrayInt::New());
5155 newConnI->alloc(nbOf3DCells+1,1);
5156 int *newConnIPtr(newConnI->getPointer());
5158 std::vector<int> newc;
5159 for(int j=0;j<nbOf2DCells;j++)
5161 AppendExtrudedCell(conn+connI[j],conn+connI[j+1],nbOfNodesOf1Lev,isQuad,newc);
5162 *newConnIPtr++=(int)newc.size();
5164 newConn->alloc((int)(newc.size())*nbOf1DCells,1);
5165 int *newConnPtr(newConn->getPointer());
5166 int deltaPerLev(isQuad?2*nbOfNodesOf1Lev:nbOfNodesOf1Lev);
5167 newConnIPtr=newConnI->getPointer();
5168 for(int iz=0;iz<nbOf1DCells;iz++)
5171 std::transform(newConnIPtr+1,newConnIPtr+1+nbOf2DCells,newConnIPtr+1+iz*nbOf2DCells,std::bind2nd(std::plus<int>(),newConnIPtr[iz*nbOf2DCells]));
5172 const int *posOfTypeOfCell(newConnIPtr);
5173 for(std::vector<int>::const_iterator iter=newc.begin();iter!=newc.end();iter++,newConnPtr++)
5175 int icell((int)(iter-newc.begin()));//std::distance unfortunately cannot been called here in C++98
5176 if(icell!=*posOfTypeOfCell)
5179 *newConnPtr=(*iter)+iz*deltaPerLev;
5190 ret->setConnectivity(newConn,newConnI,true);
5191 ret->setCoords(getCoords());
5196 * Checks if \a this mesh is constituted by only quadratic cells.
5197 * \return bool - \c true if there are only quadratic cells in \a this mesh.
5198 * \throw If the coordinates array is not set.
5199 * \throw If the nodal connectivity of cells is not defined.
5201 bool MEDCouplingUMesh::isFullyQuadratic() const
5203 checkFullyDefined();
5205 int nbOfCells=getNumberOfCells();
5206 for(int i=0;i<nbOfCells && ret;i++)
5208 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5209 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5210 ret=cm.isQuadratic();
5216 * Checks if \a this mesh includes any quadratic cell.
5217 * \return bool - \c true if there is at least one quadratic cells in \a this mesh.
5218 * \throw If the coordinates array is not set.
5219 * \throw If the nodal connectivity of cells is not defined.
5221 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
5223 checkFullyDefined();
5225 int nbOfCells=getNumberOfCells();
5226 for(int i=0;i<nbOfCells && !ret;i++)
5228 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5229 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5230 ret=cm.isQuadratic();
5236 * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
5237 * this mesh, it remains unchanged.
5238 * \throw If the coordinates array is not set.
5239 * \throw If the nodal connectivity of cells is not defined.
5241 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
5243 checkFullyDefined();
5244 int nbOfCells(getNumberOfCells());
5246 const int *iciptr=_nodal_connec_index->begin();
5247 for(int i=0;i<nbOfCells;i++)
5249 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5250 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5251 if(cm.isQuadratic())
5253 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
5254 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
5255 if(!cml.isDynamic())
5256 delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
5258 delta+=(iciptr[i+1]-iciptr[i]-1)/2;
5263 MCAuto<DataArrayInt> newConn(DataArrayInt::New()),newConnI(DataArrayInt::New());
5264 const int *icptr(_nodal_connec->begin());
5265 newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
5266 newConnI->alloc(nbOfCells+1,1);
5267 int *ocptr(newConn->getPointer()),*ociptr(newConnI->getPointer());
5270 for(int i=0;i<nbOfCells;i++,ociptr++)
5272 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
5273 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5274 if(!cm.isQuadratic())
5276 _types.insert(type);
5277 ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
5278 ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
5282 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
5283 _types.insert(typel);
5284 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
5285 int newNbOfNodes=cml.getNumberOfNodes();
5287 newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
5288 *ocptr++=(int)typel;
5289 ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
5290 ociptr[1]=ociptr[0]+newNbOfNodes+1;
5293 setConnectivity(newConn,newConnI,false);
5297 * This method converts all linear cell in \a this to quadratic one.
5298 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
5299 * 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)
5300 * 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.
5301 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
5302 * end of the existing coordinates.
5304 * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
5305 * corresponding quadratic cells. 1 is those creating the 'most' complex.
5306 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5308 * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
5310 * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
5312 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
5314 DataArrayInt *conn=0,*connI=0;
5315 DataArrayDouble *coords=0;
5316 std::set<INTERP_KERNEL::NormalizedCellType> types;
5317 checkFullyDefined();
5318 MCAuto<DataArrayInt> ret,connSafe,connISafe;
5319 MCAuto<DataArrayDouble> coordsSafe;
5320 int meshDim=getMeshDimension();
5321 switch(conversionType)
5327 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
5328 connSafe=conn; connISafe=connI; coordsSafe=coords;
5331 ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
5332 connSafe=conn; connISafe=connI; coordsSafe=coords;
5335 ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
5336 connSafe=conn; connISafe=connI; coordsSafe=coords;
5339 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
5347 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
5348 connSafe=conn; connISafe=connI; coordsSafe=coords;
5351 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
5352 connSafe=conn; connISafe=connI; coordsSafe=coords;
5355 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
5356 connSafe=conn; connISafe=connI; coordsSafe=coords;
5359 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
5364 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
5366 setConnectivity(connSafe,connISafe,false);
5368 setCoords(coordsSafe);
5373 * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
5374 * so that the number of cells remains the same. Quadratic faces are converted to
5375 * polygons. This method works only for 2D meshes in
5376 * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
5377 * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
5378 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5379 * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
5380 * a polylinized edge constituting the input polygon.
5381 * \throw If the coordinates array is not set.
5382 * \throw If the nodal connectivity of cells is not defined.
5383 * \throw If \a this->getMeshDimension() != 2.
5384 * \throw If \a this->getSpaceDimension() != 2.
5386 void MEDCouplingUMesh::tessellate2D(double eps)
5388 int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
5390 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
5394 return tessellate2DCurveInternal(eps);
5396 return tessellate2DInternal(eps);
5398 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
5402 * Tessellates \a this 1D mesh in 2D space by dividing not straight quadratic edges.
5403 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5404 * \param [in] eps - specifies the maximal angle (in radian) between 2 sub-edges of
5405 * a sub-divided edge.
5406 * \throw If the coordinates array is not set.
5407 * \throw If the nodal connectivity of cells is not defined.
5408 * \throw If \a this->getMeshDimension() != 1.
5409 * \throw If \a this->getSpaceDimension() != 2.
5414 * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
5415 * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
5416 * The nodes to be added in those 2D cells are defined by the pair of \a nodeIdsToAdd and \a nodeIdsIndexToAdd.
5417 * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
5418 * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
5419 * This method can be seen as the opposite method of colinearize2D.
5420 * 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
5421 * to avoid to modify the numbering of existing nodes.
5423 * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
5424 * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
5425 * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
5426 * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
5427 * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
5428 * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
5429 * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
5431 * \sa buildDescendingConnectivity2
5433 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayInt *nodeIdsToAdd, const DataArrayInt *nodeIdsIndexToAdd, const DataArrayInt *edgeIdsToBeSplit,
5434 const MEDCouplingUMesh *mesh1Desc, const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *revDesc, const DataArrayInt *revDescI)
5436 if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
5437 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
5438 nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
5439 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
5440 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
5441 if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
5442 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
5443 //DataArrayInt *out0(0),*outi0(0);
5444 //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
5445 //MCAuto<DataArrayInt> out0s(out0),outi0s(outi0);
5446 //out0s=out0s->buildUnique(); out0s->sort(true);
5451 * Implementes \a conversionType 0 for meshes with meshDim = 1, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5452 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5453 * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5455 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic1D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5457 MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5458 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5459 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5460 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5461 int nbOfCells=getNumberOfCells();
5462 int nbOfNodes=getNumberOfNodes();
5463 const int *cPtr=_nodal_connec->begin();
5464 const int *icPtr=_nodal_connec_index->begin();
5465 int lastVal=0,offset=nbOfNodes;
5466 for(int i=0;i<nbOfCells;i++,icPtr++)
5468 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5469 if(type==INTERP_KERNEL::NORM_SEG2)
5471 types.insert(INTERP_KERNEL::NORM_SEG3);
5472 newConn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG3);
5473 newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[0]+3);
5474 newConn->pushBackSilent(offset++);
5476 newConnI->pushBackSilent(lastVal);
5477 ret->pushBackSilent(i);
5482 lastVal+=(icPtr[1]-icPtr[0]);
5483 newConnI->pushBackSilent(lastVal);
5484 newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5487 MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5488 coords=DataArrayDouble::Aggregate(getCoords(),tmp); conn=newConn.retn(); connI=newConnI.retn();
5492 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
5494 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5495 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5496 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5498 const int *descPtr(desc->begin()),*descIPtr(descI->begin());
5499 DataArrayInt *conn1D=0,*conn1DI=0;
5500 std::set<INTERP_KERNEL::NormalizedCellType> types1D;
5501 DataArrayDouble *coordsTmp=0;
5502 MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=0;
5503 MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5504 MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5505 const int *c1DPtr=conn1D->begin();
5506 const int *c1DIPtr=conn1DI->begin();
5507 int nbOfCells=getNumberOfCells();
5508 const int *cPtr=_nodal_connec->begin();
5509 const int *icPtr=_nodal_connec_index->begin();
5511 for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++)
5513 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5514 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5515 if(!cm.isQuadratic())
5517 INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType();
5518 types.insert(typ2); newConn->pushBackSilent(typ2);
5519 newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5520 for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5521 newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5522 lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0]);
5523 newConnI->pushBackSilent(lastVal);
5524 ret->pushBackSilent(i);
5529 lastVal+=(icPtr[1]-icPtr[0]);
5530 newConnI->pushBackSilent(lastVal);
5531 newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5534 conn=newConn.retn(); connI=newConnI.retn(); coords=coordsTmpSafe.retn();
5539 * Implementes \a conversionType 0 for meshes with meshDim = 2, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5540 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5541 * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5543 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic2D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5545 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5546 MCAuto<MEDCouplingUMesh> m1D=buildDescendingConnectivity(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5547 return convertLinearCellsToQuadratic2DAnd3D0(m1D,desc,descI,conn,connI,coords,types);
5550 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic2D1(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5552 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5553 MCAuto<MEDCouplingUMesh> m1D=buildDescendingConnectivity(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5555 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5556 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5557 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5559 MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5560 const int *descPtr(desc->begin()),*descIPtr(descI->begin());
5561 DataArrayInt *conn1D=0,*conn1DI=0;
5562 std::set<INTERP_KERNEL::NormalizedCellType> types1D;
5563 DataArrayDouble *coordsTmp=0;
5564 MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=0;
5565 MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5566 MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5567 const int *c1DPtr=conn1D->begin();
5568 const int *c1DIPtr=conn1DI->begin();
5569 int nbOfCells=getNumberOfCells();
5570 const int *cPtr=_nodal_connec->begin();
5571 const int *icPtr=_nodal_connec_index->begin();
5572 int lastVal=0,offset=coordsTmpSafe->getNumberOfTuples();
5573 for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++)
5575 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5576 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5577 if(!cm.isQuadratic())
5579 INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType2();
5580 types.insert(typ2); newConn->pushBackSilent(typ2);
5581 newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5582 for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5583 newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5584 newConn->pushBackSilent(offset+ret->getNumberOfTuples());
5585 lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0])+1;
5586 newConnI->pushBackSilent(lastVal);
5587 ret->pushBackSilent(i);
5592 lastVal+=(icPtr[1]-icPtr[0]);
5593 newConnI->pushBackSilent(lastVal);
5594 newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5597 MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5598 coords=DataArrayDouble::Aggregate(coordsTmpSafe,tmp); conn=newConn.retn(); connI=newConnI.retn();
5603 * Implementes \a conversionType 0 for meshes with meshDim = 3, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5604 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5605 * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5607 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic3D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5609 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5610 MCAuto<MEDCouplingUMesh> m1D=explode3DMeshTo1D(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5611 return convertLinearCellsToQuadratic2DAnd3D0(m1D,desc,descI,conn,connI,coords,types);
5614 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic3D1(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5616 MCAuto<DataArrayInt> desc2(DataArrayInt::New()),desc2I(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5617 MCAuto<MEDCouplingUMesh> m2D=buildDescendingConnectivityGen<MinusOneSonsGeneratorBiQuadratic>(desc2,desc2I,tmp2,tmp3,MEDCouplingFastNbrer); tmp2=0; tmp3=0;
5618 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),desc1I(DataArrayInt::New()),tmp4(DataArrayInt::New()),tmp5(DataArrayInt::New());
5619 MCAuto<MEDCouplingUMesh> m1D=explode3DMeshTo1D(desc1,desc1I,tmp4,tmp5); tmp4=0; tmp5=0;
5621 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5622 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5623 MCAuto<DataArrayInt> ret=DataArrayInt::New(),ret2=DataArrayInt::New(); ret->alloc(0,1); ret2->alloc(0,1);
5625 MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5626 const int *descPtr(desc1->begin()),*descIPtr(desc1I->begin()),*desc2Ptr(desc2->begin()),*desc2IPtr(desc2I->begin());
5627 DataArrayInt *conn1D=0,*conn1DI=0,*conn2D=0,*conn2DI=0;
5628 std::set<INTERP_KERNEL::NormalizedCellType> types1D,types2D;
5629 DataArrayDouble *coordsTmp=0,*coordsTmp2=0;
5630 MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=DataArrayInt::New(); ret1D->alloc(0,1);
5631 MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5632 MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5633 MCAuto<DataArrayInt> ret2D=m2D->convertLinearCellsToQuadratic2D1(conn2D,conn2DI,coordsTmp2,types2D); ret2D=DataArrayInt::New(); ret2D->alloc(0,1);
5634 MCAuto<DataArrayDouble> coordsTmp2Safe(coordsTmp2);
5635 MCAuto<DataArrayInt> conn2DSafe(conn2D),conn2DISafe(conn2DI);
5636 const int *c1DPtr=conn1D->begin(),*c1DIPtr=conn1DI->begin(),*c2DPtr=conn2D->begin(),*c2DIPtr=conn2DI->begin();
5637 int nbOfCells=getNumberOfCells();
5638 const int *cPtr=_nodal_connec->begin();
5639 const int *icPtr=_nodal_connec_index->begin();
5640 int lastVal=0,offset=coordsTmpSafe->getNumberOfTuples();
5641 for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++,desc2IPtr++)
5643 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5644 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5645 if(!cm.isQuadratic())
5647 INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType2();
5648 if(typ2==INTERP_KERNEL::NORM_ERROR)
5650 std::ostringstream oss; oss << "MEDCouplingUMesh::convertLinearCellsToQuadratic3D1 : On cell #" << i << " the linear cell type does not support advanced quadratization !";
5651 throw INTERP_KERNEL::Exception(oss.str());
5653 types.insert(typ2); newConn->pushBackSilent(typ2);
5654 newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5655 for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5656 newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5657 for(const int *d=desc2Ptr+desc2IPtr[0];d!=desc2Ptr+desc2IPtr[1];d++)
5659 int nodeId2=c2DPtr[c2DIPtr[(*d)+1]-1];
5660 int tmpPos=newConn->getNumberOfTuples();
5661 newConn->pushBackSilent(nodeId2);
5662 ret2D->pushBackSilent(nodeId2); ret1D->pushBackSilent(tmpPos);
5664 newConn->pushBackSilent(offset+ret->getNumberOfTuples());
5665 lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0])+(desc2IPtr[1]-desc2IPtr[0])+1;
5666 newConnI->pushBackSilent(lastVal);
5667 ret->pushBackSilent(i);
5672 lastVal+=(icPtr[1]-icPtr[0]);
5673 newConnI->pushBackSilent(lastVal);
5674 newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5677 MCAuto<DataArrayInt> diffRet2D=ret2D->getDifferentValues();
5678 MCAuto<DataArrayInt> o2nRet2D=diffRet2D->invertArrayN2O2O2N(coordsTmp2Safe->getNumberOfTuples());
5679 coordsTmp2Safe=coordsTmp2Safe->selectByTupleId(diffRet2D->begin(),diffRet2D->end());
5680 MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5681 std::vector<const DataArrayDouble *> v(3); v[0]=coordsTmpSafe; v[1]=coordsTmp2Safe; v[2]=tmp;
5682 int *c=newConn->getPointer();
5683 const int *cI(newConnI->begin());
5684 for(const int *elt=ret1D->begin();elt!=ret1D->end();elt++)
5685 c[*elt]=o2nRet2D->getIJ(c[*elt],0)+offset;
5686 offset=coordsTmp2Safe->getNumberOfTuples();
5687 for(const int *elt=ret->begin();elt!=ret->end();elt++)
5688 c[cI[(*elt)+1]-1]+=offset;
5689 coords=DataArrayDouble::Aggregate(v); conn=newConn.retn(); connI=newConnI.retn();
5694 * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
5695 * In addition, returns an array mapping new cells to old ones. <br>
5696 * This method typically increases the number of cells in \a this mesh
5697 * but the number of nodes remains \b unchanged.
5698 * That's why the 3D splitting policies
5699 * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
5700 * \param [in] policy - specifies a pattern used for splitting.
5701 * The semantic of \a policy is:
5702 * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
5703 * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
5704 * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8 into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
5705 * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8 into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
5708 * \return DataArrayInt * - a new instance of DataArrayInt holding, for each new cell,
5709 * an id of old cell producing it. The caller is to delete this array using
5710 * decrRef() as it is no more needed.
5712 * \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
5713 * \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
5714 * and \a this->getMeshDimension() != 3.
5715 * \throw If \a policy is not one of the four discussed above.
5716 * \throw If the nodal connectivity of cells is not defined.
5717 * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
5719 DataArrayInt *MEDCouplingUMesh::simplexize(int policy)
5724 return simplexizePol0();
5726 return simplexizePol1();
5727 case (int) INTERP_KERNEL::PLANAR_FACE_5:
5728 return simplexizePlanarFace5();
5729 case (int) INTERP_KERNEL::PLANAR_FACE_6:
5730 return simplexizePlanarFace6();
5732 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)");
5737 * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
5738 * - 1D: INTERP_KERNEL::NORM_SEG2
5739 * - 2D: INTERP_KERNEL::NORM_TRI3
5740 * - 3D: INTERP_KERNEL::NORM_TETRA4.
5742 * This method is useful for users that need to use P1 field services as
5743 * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
5744 * All these methods need mesh support containing only simplex cells.
5745 * \return bool - \c true if there are only simplex cells in \a this mesh.
5746 * \throw If the coordinates array is not set.
5747 * \throw If the nodal connectivity of cells is not defined.
5748 * \throw If \a this->getMeshDimension() < 1.
5750 bool MEDCouplingUMesh::areOnlySimplexCells() const
5752 checkFullyDefined();
5753 int mdim=getMeshDimension();
5754 if(mdim<1 || mdim>3)
5755 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
5756 int nbCells=getNumberOfCells();
5757 const int *conn=_nodal_connec->begin();
5758 const int *connI=_nodal_connec_index->begin();
5759 for(int i=0;i<nbCells;i++)
5761 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5769 * This method implements policy 0 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5771 DataArrayInt *MEDCouplingUMesh::simplexizePol0()
5773 checkConnectivityFullyDefined();
5774 if(getMeshDimension()!=2)
5775 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePol0 : this policy is only available for mesh with meshdim == 2 !");
5776 int nbOfCells=getNumberOfCells();
5777 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5778 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_QUAD4);
5779 ret->alloc(nbOfCells+nbOfCutCells,1);
5780 if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5781 int *retPt=ret->getPointer();
5782 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5783 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5784 newConnI->alloc(nbOfCells+nbOfCutCells+1,1);
5785 newConn->alloc(getNodalConnectivityArrayLen()+3*nbOfCutCells,1);
5786 int *pt=newConn->getPointer();
5787 int *ptI=newConnI->getPointer();
5789 const int *oldc=_nodal_connec->begin();
5790 const int *ci=_nodal_connec_index->begin();
5791 for(int i=0;i<nbOfCells;i++,ci++)
5793 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_QUAD4)
5795 const int tmp[8]={(int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+2],oldc[ci[0]+3],
5796 (int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+3],oldc[ci[0]+4]};
5797 pt=std::copy(tmp,tmp+8,pt);
5806 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5807 ptI[1]=ptI[0]+ci[1]-ci[0];
5812 _nodal_connec->decrRef();
5813 _nodal_connec=newConn.retn();
5814 _nodal_connec_index->decrRef();
5815 _nodal_connec_index=newConnI.retn();
5822 * This method implements policy 1 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5824 DataArrayInt *MEDCouplingUMesh::simplexizePol1()
5826 checkConnectivityFullyDefined();
5827 if(getMeshDimension()!=2)
5828 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePol0 : this policy is only available for mesh with meshdim == 2 !");
5829 int nbOfCells=getNumberOfCells();
5830 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5831 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_QUAD4);
5832 ret->alloc(nbOfCells+nbOfCutCells,1);
5833 if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5834 int *retPt=ret->getPointer();
5835 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5836 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5837 newConnI->alloc(nbOfCells+nbOfCutCells+1,1);
5838 newConn->alloc(getNodalConnectivityArrayLen()+3*nbOfCutCells,1);
5839 int *pt=newConn->getPointer();
5840 int *ptI=newConnI->getPointer();
5842 const int *oldc=_nodal_connec->begin();
5843 const int *ci=_nodal_connec_index->begin();
5844 for(int i=0;i<nbOfCells;i++,ci++)
5846 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_QUAD4)
5848 const int tmp[8]={(int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+2],oldc[ci[0]+4],
5849 (int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+2],oldc[ci[0]+3],oldc[ci[0]+4]};
5850 pt=std::copy(tmp,tmp+8,pt);
5859 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5860 ptI[1]=ptI[0]+ci[1]-ci[0];
5865 _nodal_connec->decrRef();
5866 _nodal_connec=newConn.retn();
5867 _nodal_connec_index->decrRef();
5868 _nodal_connec_index=newConnI.retn();
5875 * This method implements policy INTERP_KERNEL::PLANAR_FACE_5 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5877 DataArrayInt *MEDCouplingUMesh::simplexizePlanarFace5()
5879 checkConnectivityFullyDefined();
5880 if(getMeshDimension()!=3)
5881 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePlanarFace5 : this policy is only available for mesh with meshdim == 3 !");
5882 int nbOfCells=getNumberOfCells();
5883 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5884 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_HEXA8);
5885 ret->alloc(nbOfCells+4*nbOfCutCells,1);
5886 if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5887 int *retPt=ret->getPointer();
5888 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5889 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5890 newConnI->alloc(nbOfCells+4*nbOfCutCells+1,1);
5891 newConn->alloc(getNodalConnectivityArrayLen()+16*nbOfCutCells,1);//21
5892 int *pt=newConn->getPointer();
5893 int *ptI=newConnI->getPointer();
5895 const int *oldc=_nodal_connec->begin();
5896 const int *ci=_nodal_connec_index->begin();
5897 for(int i=0;i<nbOfCells;i++,ci++)
5899 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_HEXA8)
5901 for(int j=0;j<5;j++,pt+=5,ptI++)
5903 pt[0]=(int)INTERP_KERNEL::NORM_TETRA4;
5904 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];
5911 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5912 ptI[1]=ptI[0]+ci[1]-ci[0];
5917 _nodal_connec->decrRef();
5918 _nodal_connec=newConn.retn();
5919 _nodal_connec_index->decrRef();
5920 _nodal_connec_index=newConnI.retn();
5927 * This method implements policy INTERP_KERNEL::PLANAR_FACE_6 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5929 DataArrayInt *MEDCouplingUMesh::simplexizePlanarFace6()
5931 checkConnectivityFullyDefined();
5932 if(getMeshDimension()!=3)
5933 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePlanarFace6 : this policy is only available for mesh with meshdim == 3 !");
5934 int nbOfCells=getNumberOfCells();
5935 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5936 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_HEXA8);
5937 ret->alloc(nbOfCells+5*nbOfCutCells,1);
5938 if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5939 int *retPt=ret->getPointer();
5940 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5941 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5942 newConnI->alloc(nbOfCells+5*nbOfCutCells+1,1);
5943 newConn->alloc(getNodalConnectivityArrayLen()+21*nbOfCutCells,1);
5944 int *pt=newConn->getPointer();
5945 int *ptI=newConnI->getPointer();
5947 const int *oldc=_nodal_connec->begin();
5948 const int *ci=_nodal_connec_index->begin();
5949 for(int i=0;i<nbOfCells;i++,ci++)
5951 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_HEXA8)
5953 for(int j=0;j<6;j++,pt+=5,ptI++)
5955 pt[0]=(int)INTERP_KERNEL::NORM_TETRA4;
5956 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];
5963 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5964 ptI[1]=ptI[0]+ci[1]-ci[0];
5969 _nodal_connec->decrRef();
5970 _nodal_connec=newConn.retn();
5971 _nodal_connec_index->decrRef();
5972 _nodal_connec_index=newConnI.retn();
5979 * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
5980 * so that the number of cells remains the same. Quadratic faces are converted to
5981 * polygons. This method works only for 2D meshes in
5982 * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
5983 * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
5984 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5985 * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
5986 * a polylinized edge constituting the input polygon.
5987 * \throw If the coordinates array is not set.
5988 * \throw If the nodal connectivity of cells is not defined.
5989 * \throw If \a this->getMeshDimension() != 2.
5990 * \throw If \a this->getSpaceDimension() != 2.
5992 void MEDCouplingUMesh::tessellate2DInternal(double eps)
5994 checkFullyDefined();
5995 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
5996 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DInternal works on umeshes with meshdim equal to 2 and spaceDim equal to 2 too!");
5997 double epsa=fabs(eps);
5998 if(epsa<std::numeric_limits<double>::min())
5999 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 !");
6000 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
6001 MCAuto<MEDCouplingUMesh> mDesc(buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1));
6002 revDesc1=0; revDescIndx1=0;
6003 mDesc->tessellate2D(eps);
6004 subDivide2DMesh(mDesc->_nodal_connec->begin(),mDesc->_nodal_connec_index->begin(),desc1->begin(),descIndx1->begin());
6005 setCoords(mDesc->getCoords());
6009 * Tessellates \a this 1D mesh in 2D space by dividing not straight quadratic edges.
6010 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
6011 * \param [in] eps - specifies the maximal angle (in radian) between 2 sub-edges of
6012 * a sub-divided edge.
6013 * \throw If the coordinates array is not set.
6014 * \throw If the nodal connectivity of cells is not defined.
6015 * \throw If \a this->getMeshDimension() != 1.
6016 * \throw If \a this->getSpaceDimension() != 2.
6018 void MEDCouplingUMesh::tessellate2DCurveInternal(double eps)
6020 checkFullyDefined();
6021 if(getMeshDimension()!=1 || getSpaceDimension()!=2)
6022 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DCurveInternal works on umeshes with meshdim equal to 1 and spaceDim equal to 2 too!");
6023 double epsa=fabs(eps);
6024 if(epsa<std::numeric_limits<double>::min())
6025 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 !");
6026 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=1.e-10;
6027 int nbCells=getNumberOfCells();
6028 int nbNodes=getNumberOfNodes();
6029 const int *conn=_nodal_connec->begin();
6030 const int *connI=_nodal_connec_index->begin();
6031 const double *coords=_coords->begin();
6032 std::vector<double> addCoo;
6033 std::vector<int> newConn;//no direct DataArrayInt because interface with Geometric2D
6034 MCAuto<DataArrayInt> newConnI(DataArrayInt::New());
6035 newConnI->alloc(nbCells+1,1);
6036 int *newConnIPtr=newConnI->getPointer();
6039 INTERP_KERNEL::Node *tmp2[3];
6040 std::set<INTERP_KERNEL::NormalizedCellType> types;
6041 for(int i=0;i<nbCells;i++,newConnIPtr++)
6043 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6044 if(cm.isQuadratic())
6045 {//assert(connI[i+1]-connI[i]-1==3)
6046 tmp1[0]=conn[connI[i]+1+0]; tmp1[1]=conn[connI[i]+1+1]; tmp1[2]=conn[connI[i]+1+2];
6047 tmp2[0]=new INTERP_KERNEL::Node(coords[2*tmp1[0]],coords[2*tmp1[0]+1]);
6048 tmp2[1]=new INTERP_KERNEL::Node(coords[2*tmp1[1]],coords[2*tmp1[1]+1]);
6049 tmp2[2]=new INTERP_KERNEL::Node(coords[2*tmp1[2]],coords[2*tmp1[2]+1]);
6050 INTERP_KERNEL::EdgeArcCircle *eac=INTERP_KERNEL::EdgeArcCircle::BuildFromNodes(tmp2[0],tmp2[2],tmp2[1]);
6053 eac->tesselate(tmp1,nbNodes,epsa,newConn,addCoo);
6054 types.insert((INTERP_KERNEL::NormalizedCellType)newConn[newConnIPtr[0]]);
6056 newConnIPtr[1]=(int)newConn.size();
6060 types.insert(INTERP_KERNEL::NORM_SEG2);
6061 newConn.push_back(INTERP_KERNEL::NORM_SEG2);
6062 newConn.insert(newConn.end(),conn+connI[i]+1,conn+connI[i]+3);
6063 newConnIPtr[1]=newConnIPtr[0]+3;
6068 types.insert((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6069 newConn.insert(newConn.end(),conn+connI[i],conn+connI[i+1]);
6070 newConnIPtr[1]=newConnIPtr[0]+3;
6073 if(addCoo.empty() && ((int)newConn.size())==_nodal_connec->getNumberOfTuples())//nothing happens during tessellation : no update needed
6076 DataArrayInt::SetArrayIn(newConnI,_nodal_connec_index);
6077 MCAuto<DataArrayInt> newConnArr=DataArrayInt::New();
6078 newConnArr->alloc((int)newConn.size(),1);
6079 std::copy(newConn.begin(),newConn.end(),newConnArr->getPointer());
6080 DataArrayInt::SetArrayIn(newConnArr,_nodal_connec);
6081 MCAuto<DataArrayDouble> newCoords=DataArrayDouble::New();
6082 newCoords->alloc(nbNodes+((int)addCoo.size())/2,2);
6083 double *work=std::copy(_coords->begin(),_coords->end(),newCoords->getPointer());
6084 std::copy(addCoo.begin(),addCoo.end(),work);
6085 DataArrayDouble::SetArrayIn(newCoords,_coords);
6090 * 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.
6091 * This method completly ignore coordinates.
6092 * \param nodeSubdived is the nodal connectivity of subdivision of edges
6093 * \param nodeIndxSubdived is the nodal connectivity index of subdivision of edges
6094 * \param desc is descending connectivity in format specified in MEDCouplingUMesh::buildDescendingConnectivity2
6095 * \param descIndex is descending connectivity index in format specified in MEDCouplingUMesh::buildDescendingConnectivity2
6097 void MEDCouplingUMesh::subDivide2DMesh(const int *nodeSubdived, const int *nodeIndxSubdived, const int *desc, const int *descIndex)
6099 checkFullyDefined();
6100 if(getMeshDimension()!=2)
6101 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::subDivide2DMesh : works only on umesh with meshdim==2 !");
6102 int nbOfCells=getNumberOfCells();
6103 int *connI=_nodal_connec_index->getPointer();
6105 for(int i=0;i<nbOfCells;i++,connI++)
6107 int offset=descIndex[i];
6108 int nbOfEdges=descIndex[i+1]-offset;
6110 bool ddirect=desc[offset+nbOfEdges-1]>0;
6111 int eedgeId=std::abs(desc[offset+nbOfEdges-1])-1;
6112 int ref=ddirect?nodeSubdived[nodeIndxSubdived[eedgeId+1]-1]:nodeSubdived[nodeIndxSubdived[eedgeId]+1];
6113 for(int j=0;j<nbOfEdges;j++)
6115 bool direct=desc[offset+j]>0;
6116 int edgeId=std::abs(desc[offset+j])-1;
6117 if(!INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodeSubdived[nodeIndxSubdived[edgeId]]).isQuadratic())
6119 int id1=nodeSubdived[nodeIndxSubdived[edgeId]+1];
6120 int id2=nodeSubdived[nodeIndxSubdived[edgeId+1]-1];
6121 int ref2=direct?id1:id2;
6124 int nbOfSubNodes=nodeIndxSubdived[edgeId+1]-nodeIndxSubdived[edgeId]-1;
6125 newConnLgth+=nbOfSubNodes-1;
6130 std::ostringstream oss; oss << "MEDCouplingUMesh::subDivide2DMesh : On polygon #" << i << " edgeid #" << j << " subedges mismatch : end subedge k!=start subedge k+1 !";
6131 throw INTERP_KERNEL::Exception(oss.str());
6136 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::subDivide2DMesh : this method only subdivides into linear edges !");
6139 newConnLgth++;//+1 is for cell type
6140 connI[1]=newConnLgth;
6143 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
6144 newConn->alloc(newConnLgth,1);
6145 int *work=newConn->getPointer();
6146 for(int i=0;i<nbOfCells;i++)
6148 *work++=INTERP_KERNEL::NORM_POLYGON;
6149 int offset=descIndex[i];
6150 int nbOfEdges=descIndex[i+1]-offset;
6151 for(int j=0;j<nbOfEdges;j++)
6153 bool direct=desc[offset+j]>0;
6154 int edgeId=std::abs(desc[offset+j])-1;
6156 work=std::copy(nodeSubdived+nodeIndxSubdived[edgeId]+1,nodeSubdived+nodeIndxSubdived[edgeId+1]-1,work);
6159 int nbOfSubNodes=nodeIndxSubdived[edgeId+1]-nodeIndxSubdived[edgeId]-1;
6160 std::reverse_iterator<const int *> it(nodeSubdived+nodeIndxSubdived[edgeId+1]);
6161 work=std::copy(it,it+nbOfSubNodes-1,work);
6165 DataArrayInt::SetArrayIn(newConn,_nodal_connec);
6168 _types.insert(INTERP_KERNEL::NORM_POLYGON);
6172 * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
6173 * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
6174 * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell. This method
6175 * does \b not perform geometrical checks and checks only nodal connectivity of cells,
6176 * so it can be useful to call mergeNodes() before calling this method.
6177 * \throw If \a this->getMeshDimension() <= 1.
6178 * \throw If the coordinates array is not set.
6179 * \throw If the nodal connectivity of cells is not defined.
6181 void MEDCouplingUMesh::convertDegeneratedCells()
6183 checkFullyDefined();
6184 if(getMeshDimension()<=1)
6185 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
6186 int nbOfCells=getNumberOfCells();
6189 int initMeshLgth=getNodalConnectivityArrayLen();
6190 int *conn=_nodal_connec->getPointer();
6191 int *index=_nodal_connec_index->getPointer();
6195 for(int i=0;i<nbOfCells;i++)
6197 lgthOfCurCell=index[i+1]-posOfCurCell;
6198 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
6200 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
6201 conn+newPos+1,newLgth);
6202 conn[newPos]=newType;
6204 posOfCurCell=index[i+1];
6207 if(newPos!=initMeshLgth)
6208 _nodal_connec->reAlloc(newPos);
6213 * Finds incorrectly oriented cells of this 2D mesh in 3D space.
6214 * A cell is considered to be oriented correctly if an angle between its
6215 * normal vector and a given vector is less than \c PI / \c 2.
6216 * \param [in] vec - 3 components of the vector specifying the correct orientation of
6218 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
6220 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
6221 * is not cleared before filling in.
6222 * \throw If \a this->getMeshDimension() != 2.
6223 * \throw If \a this->getSpaceDimension() != 3.
6225 * \if ENABLE_EXAMPLES
6226 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
6227 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
6230 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<int>& cells) const
6232 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6233 throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
6234 int nbOfCells=getNumberOfCells();
6235 const int *conn=_nodal_connec->begin();
6236 const int *connI=_nodal_connec_index->begin();
6237 const double *coordsPtr=_coords->begin();
6238 for(int i=0;i<nbOfCells;i++)
6240 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6241 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
6243 bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
6244 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6251 * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
6252 * considered to be oriented correctly if an angle between its normal vector and a
6253 * given vector is less than \c PI / \c 2.
6254 * \param [in] vec - 3 components of the vector specifying the correct orientation of
6256 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
6258 * \throw If \a this->getMeshDimension() != 2.
6259 * \throw If \a this->getSpaceDimension() != 3.
6261 * \if ENABLE_EXAMPLES
6262 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
6263 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
6266 * \sa changeOrientationOfCells
6268 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
6270 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6271 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
6272 int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
6273 const int *connI(_nodal_connec_index->begin());
6274 const double *coordsPtr(_coords->begin());
6275 bool isModified(false);
6276 for(int i=0;i<nbOfCells;i++)
6278 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6279 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
6281 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6282 bool isQuadratic(cm.isQuadratic());
6283 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6286 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6291 _nodal_connec->declareAsNew();
6296 * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
6298 * \sa orientCorrectly2DCells
6300 void MEDCouplingUMesh::changeOrientationOfCells()
6302 int mdim(getMeshDimension());
6303 if(mdim!=2 && mdim!=1)
6304 throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
6305 int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
6306 const int *connI(_nodal_connec_index->begin());
6309 for(int i=0;i<nbOfCells;i++)
6311 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6312 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6313 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6318 for(int i=0;i<nbOfCells;i++)
6320 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6321 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6322 cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6328 * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
6329 * oriented facets. The normal vector of the facet should point out of the cell.
6330 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
6331 * is not cleared before filling in.
6332 * \throw If \a this->getMeshDimension() != 3.
6333 * \throw If \a this->getSpaceDimension() != 3.
6334 * \throw If the coordinates array is not set.
6335 * \throw If the nodal connectivity of cells is not defined.
6337 * \if ENABLE_EXAMPLES
6338 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
6339 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
6342 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<int>& cells) const
6344 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6345 throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
6346 int nbOfCells=getNumberOfCells();
6347 const int *conn=_nodal_connec->begin();
6348 const int *connI=_nodal_connec_index->begin();
6349 const double *coordsPtr=_coords->begin();
6350 for(int i=0;i<nbOfCells;i++)
6352 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6353 if(type==INTERP_KERNEL::NORM_POLYHED)
6355 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6362 * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
6364 * \throw If \a this->getMeshDimension() != 3.
6365 * \throw If \a this->getSpaceDimension() != 3.
6366 * \throw If the coordinates array is not set.
6367 * \throw If the nodal connectivity of cells is not defined.
6368 * \throw If the reparation fails.
6370 * \if ENABLE_EXAMPLES
6371 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
6372 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
6374 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
6376 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
6378 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6379 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
6380 int nbOfCells=getNumberOfCells();
6381 int *conn=_nodal_connec->getPointer();
6382 const int *connI=_nodal_connec_index->begin();
6383 const double *coordsPtr=_coords->begin();
6384 for(int i=0;i<nbOfCells;i++)
6386 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6387 if(type==INTERP_KERNEL::NORM_POLYHED)
6391 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6392 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
6394 catch(INTERP_KERNEL::Exception& e)
6396 std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
6397 throw INTERP_KERNEL::Exception(oss.str());
6405 * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
6406 * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
6407 * according to which the first facet of the cell should be oriented to have the normal vector
6408 * pointing out of cell.
6409 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of fixed
6410 * cells. The caller is to delete this array using decrRef() as it is no more
6412 * \throw If \a this->getMeshDimension() != 3.
6413 * \throw If \a this->getSpaceDimension() != 3.
6414 * \throw If the coordinates array is not set.
6415 * \throw If the nodal connectivity of cells is not defined.
6417 * \if ENABLE_EXAMPLES
6418 * \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
6419 * \ref py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
6421 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
6423 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
6425 const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
6426 if(getMeshDimension()!=3)
6427 throw INTERP_KERNEL::Exception(msg);
6428 int spaceDim=getSpaceDimension();
6430 throw INTERP_KERNEL::Exception(msg);
6432 int nbOfCells=getNumberOfCells();
6433 int *conn=_nodal_connec->getPointer();
6434 const int *connI=_nodal_connec_index->begin();
6435 const double *coo=getCoords()->begin();
6436 MCAuto<DataArrayInt> cells(DataArrayInt::New()); cells->alloc(0,1);
6437 for(int i=0;i<nbOfCells;i++)
6439 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6440 if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
6442 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
6444 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
6445 cells->pushBackSilent(i);
6449 return cells.retn();
6453 * This method is a faster method to correct orientation of all 3D cells in \a this.
6454 * 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.
6455 * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
6457 * \return a newly allocated int array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
6458 * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
6460 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
6462 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6463 throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
6464 int nbOfCells=getNumberOfCells();
6465 int *conn=_nodal_connec->getPointer();
6466 const int *connI=_nodal_connec_index->begin();
6467 const double *coordsPtr=_coords->begin();
6468 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
6469 for(int i=0;i<nbOfCells;i++)
6471 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6474 case INTERP_KERNEL::NORM_TETRA4:
6476 if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6478 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
6479 ret->pushBackSilent(i);
6483 case INTERP_KERNEL::NORM_PYRA5:
6485 if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6487 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
6488 ret->pushBackSilent(i);
6492 case INTERP_KERNEL::NORM_PENTA6:
6493 case INTERP_KERNEL::NORM_HEXA8:
6494 case INTERP_KERNEL::NORM_HEXGP12:
6496 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6498 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
6499 ret->pushBackSilent(i);
6503 case INTERP_KERNEL::NORM_POLYHED:
6505 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6507 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
6508 ret->pushBackSilent(i);
6513 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 !");
6521 * This method has a sense for meshes with spaceDim==3 and meshDim==2.
6522 * If it is not the case an exception will be thrown.
6523 * This method is fast because the first cell of \a this is used to compute the plane.
6524 * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
6525 * \param pos output of size at least 3 used to store a point owned of searched plane.
6527 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
6529 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6530 throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
6531 const int *conn=_nodal_connec->begin();
6532 const int *connI=_nodal_connec_index->begin();
6533 const double *coordsPtr=_coords->begin();
6534 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
6535 std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
6539 * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
6540 * cells. Currently cells of the following types are treated:
6541 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
6542 * For a cell of other type an exception is thrown.
6543 * Space dimension of a 2D mesh can be either 2 or 3.
6544 * The Edge Ratio of a cell \f$t\f$ is:
6545 * \f$\frac{|t|_\infty}{|t|_0}\f$,
6546 * where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
6547 * the smallest edge lengths of \f$t\f$.
6548 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6549 * cells and one time, lying on \a this mesh. The caller is to delete this
6550 * field using decrRef() as it is no more needed.
6551 * \throw If the coordinates array is not set.
6552 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6553 * \throw If the connectivity data array has more than one component.
6554 * \throw If the connectivity data array has a named component.
6555 * \throw If the connectivity index data array has more than one component.
6556 * \throw If the connectivity index data array has a named component.
6557 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
6558 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
6559 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
6561 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
6563 checkConsistencyLight();
6564 int spaceDim=getSpaceDimension();
6565 int meshDim=getMeshDimension();
6566 if(spaceDim!=2 && spaceDim!=3)
6567 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
6568 if(meshDim!=2 && meshDim!=3)
6569 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
6570 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6572 int nbOfCells=getNumberOfCells();
6573 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6574 arr->alloc(nbOfCells,1);
6575 double *pt=arr->getPointer();
6576 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6577 const int *conn=_nodal_connec->begin();
6578 const int *connI=_nodal_connec_index->begin();
6579 const double *coo=_coords->begin();
6581 for(int i=0;i<nbOfCells;i++,pt++)
6583 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6586 case INTERP_KERNEL::NORM_TRI3:
6588 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
6589 *pt=INTERP_KERNEL::triEdgeRatio(tmp);
6592 case INTERP_KERNEL::NORM_QUAD4:
6594 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6595 *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
6598 case INTERP_KERNEL::NORM_TETRA4:
6600 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6601 *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
6605 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
6607 conn+=connI[i+1]-connI[i];
6609 ret->setName("EdgeRatio");
6610 ret->synchronizeTimeWithSupport();
6615 * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
6616 * cells. Currently cells of the following types are treated:
6617 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
6618 * For a cell of other type an exception is thrown.
6619 * Space dimension of a 2D mesh can be either 2 or 3.
6620 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6621 * cells and one time, lying on \a this mesh. The caller is to delete this
6622 * field using decrRef() as it is no more needed.
6623 * \throw If the coordinates array is not set.
6624 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6625 * \throw If the connectivity data array has more than one component.
6626 * \throw If the connectivity data array has a named component.
6627 * \throw If the connectivity index data array has more than one component.
6628 * \throw If the connectivity index data array has a named component.
6629 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
6630 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
6631 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
6633 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
6635 checkConsistencyLight();
6636 int spaceDim=getSpaceDimension();
6637 int meshDim=getMeshDimension();
6638 if(spaceDim!=2 && spaceDim!=3)
6639 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
6640 if(meshDim!=2 && meshDim!=3)
6641 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
6642 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6644 int nbOfCells=getNumberOfCells();
6645 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6646 arr->alloc(nbOfCells,1);
6647 double *pt=arr->getPointer();
6648 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6649 const int *conn=_nodal_connec->begin();
6650 const int *connI=_nodal_connec_index->begin();
6651 const double *coo=_coords->begin();
6653 for(int i=0;i<nbOfCells;i++,pt++)
6655 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6658 case INTERP_KERNEL::NORM_TRI3:
6660 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
6661 *pt=INTERP_KERNEL::triAspectRatio(tmp);
6664 case INTERP_KERNEL::NORM_QUAD4:
6666 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6667 *pt=INTERP_KERNEL::quadAspectRatio(tmp);
6670 case INTERP_KERNEL::NORM_TETRA4:
6672 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6673 *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
6677 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
6679 conn+=connI[i+1]-connI[i];
6681 ret->setName("AspectRatio");
6682 ret->synchronizeTimeWithSupport();
6687 * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
6688 * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
6689 * in 3D space. Currently only cells of the following types are
6690 * treated: INTERP_KERNEL::NORM_QUAD4.
6691 * For a cell of other type an exception is thrown.
6692 * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
6694 * \f$t=\vec{da}\times\vec{ab}\f$,
6695 * \f$u=\vec{ab}\times\vec{bc}\f$
6696 * \f$v=\vec{bc}\times\vec{cd}\f$
6697 * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
6699 * W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
6701 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6702 * cells and one time, lying on \a this mesh. The caller is to delete this
6703 * field using decrRef() as it is no more needed.
6704 * \throw If the coordinates array is not set.
6705 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6706 * \throw If the connectivity data array has more than one component.
6707 * \throw If the connectivity data array has a named component.
6708 * \throw If the connectivity index data array has more than one component.
6709 * \throw If the connectivity index data array has a named component.
6710 * \throw If \a this->getMeshDimension() != 2.
6711 * \throw If \a this->getSpaceDimension() != 3.
6712 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
6714 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
6716 checkConsistencyLight();
6717 int spaceDim=getSpaceDimension();
6718 int meshDim=getMeshDimension();
6720 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
6722 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
6723 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6725 int nbOfCells=getNumberOfCells();
6726 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6727 arr->alloc(nbOfCells,1);
6728 double *pt=arr->getPointer();
6729 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6730 const int *conn=_nodal_connec->begin();
6731 const int *connI=_nodal_connec_index->begin();
6732 const double *coo=_coords->begin();
6734 for(int i=0;i<nbOfCells;i++,pt++)
6736 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6739 case INTERP_KERNEL::NORM_QUAD4:
6741 FillInCompact3DMode(3,4,conn+1,coo,tmp);
6742 *pt=INTERP_KERNEL::quadWarp(tmp);
6746 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
6748 conn+=connI[i+1]-connI[i];
6750 ret->setName("Warp");
6751 ret->synchronizeTimeWithSupport();
6757 * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
6758 * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
6759 * treated: INTERP_KERNEL::NORM_QUAD4.
6760 * The skew is computed as follow for a quad with points (a,b,c,d): let
6761 * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
6762 * then the skew is computed as:
6764 * s=\frac{u}{|u|}\cdot\frac{v}{|v|}
6767 * For a cell of other type an exception is thrown.
6768 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6769 * cells and one time, lying on \a this mesh. The caller is to delete this
6770 * field using decrRef() as it is no more needed.
6771 * \throw If the coordinates array is not set.
6772 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6773 * \throw If the connectivity data array has more than one component.
6774 * \throw If the connectivity data array has a named component.
6775 * \throw If the connectivity index data array has more than one component.
6776 * \throw If the connectivity index data array has a named component.
6777 * \throw If \a this->getMeshDimension() != 2.
6778 * \throw If \a this->getSpaceDimension() != 3.
6779 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
6781 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
6783 checkConsistencyLight();
6784 int spaceDim=getSpaceDimension();
6785 int meshDim=getMeshDimension();
6787 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
6789 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
6790 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6792 int nbOfCells=getNumberOfCells();
6793 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6794 arr->alloc(nbOfCells,1);
6795 double *pt=arr->getPointer();
6796 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6797 const int *conn=_nodal_connec->begin();
6798 const int *connI=_nodal_connec_index->begin();
6799 const double *coo=_coords->begin();
6801 for(int i=0;i<nbOfCells;i++,pt++)
6803 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6806 case INTERP_KERNEL::NORM_QUAD4:
6808 FillInCompact3DMode(3,4,conn+1,coo,tmp);
6809 *pt=INTERP_KERNEL::quadSkew(tmp);
6813 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
6815 conn+=connI[i+1]-connI[i];
6817 ret->setName("Skew");
6818 ret->synchronizeTimeWithSupport();
6823 * 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.
6825 * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
6827 * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
6829 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
6831 checkConsistencyLight();
6832 MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
6834 std::set<INTERP_KERNEL::NormalizedCellType> types;
6835 ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
6836 int spaceDim(getSpaceDimension()),nbCells(getNumberOfCells());
6837 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6838 arr->alloc(nbCells,1);
6839 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
6841 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
6842 MCAuto<DataArrayInt> cellIds(giveCellsWithType(*it));
6843 dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
6846 ret->setName("Diameter");
6851 * This method aggregate the bbox of each cell and put it into bbox parameter (xmin,xmax,ymin,ymax,zmin,zmax).
6853 * \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)
6854 * For all other cases this input parameter is ignored.
6855 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6857 * \throw If \a this is not fully set (coordinates and connectivity).
6858 * \throw If a cell in \a this has no valid nodeId.
6859 * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
6861 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
6863 int mDim(getMeshDimension()),sDim(getSpaceDimension());
6864 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.
6865 return getBoundingBoxForBBTreeFast();
6866 if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
6868 bool presenceOfQuadratic(false);
6869 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
6871 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
6872 if(cm.isQuadratic())
6873 presenceOfQuadratic=true;
6875 if(!presenceOfQuadratic)
6876 return getBoundingBoxForBBTreeFast();
6877 if(mDim==2 && sDim==2)
6878 return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
6880 return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
6882 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) !");
6886 * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
6887 * So meshes having quadratic cells the computed bounding boxes can be invalid !
6889 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6891 * \throw If \a this is not fully set (coordinates and connectivity).
6892 * \throw If a cell in \a this has no valid nodeId.
6894 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
6896 checkFullyDefined();
6897 int spaceDim(getSpaceDimension()),nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
6898 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6899 double *bbox(ret->getPointer());
6900 for(int i=0;i<nbOfCells*spaceDim;i++)
6902 bbox[2*i]=std::numeric_limits<double>::max();
6903 bbox[2*i+1]=-std::numeric_limits<double>::max();
6905 const double *coordsPtr(_coords->begin());
6906 const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
6907 for(int i=0;i<nbOfCells;i++)
6909 int offset=connI[i]+1;
6910 int nbOfNodesForCell(connI[i+1]-offset),kk(0);
6911 for(int j=0;j<nbOfNodesForCell;j++)
6913 int nodeId=conn[offset+j];
6914 if(nodeId>=0 && nodeId<nbOfNodes)
6916 for(int k=0;k<spaceDim;k++)
6918 bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
6919 bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
6926 std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
6927 throw INTERP_KERNEL::Exception(oss.str());
6934 * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
6935 * useful for 2D meshes having quadratic cells
6936 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
6937 * the two extremities of the arc of circle).
6939 * \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)
6940 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6941 * \throw If \a this is not fully defined.
6942 * \throw If \a this is not a mesh with meshDimension equal to 2.
6943 * \throw If \a this is not a mesh with spaceDimension equal to 2.
6944 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
6946 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
6948 checkFullyDefined();
6949 int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
6950 if(spaceDim!=2 || mDim!=2)
6951 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!");
6952 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6953 double *bbox(ret->getPointer());
6954 const double *coords(_coords->begin());
6955 const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
6956 for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
6958 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
6959 int sz(connI[1]-connI[0]-1);
6960 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=arcDetEps;
6961 std::vector<INTERP_KERNEL::Node *> nodes(sz);
6962 INTERP_KERNEL::QuadraticPolygon *pol(0);
6963 for(int j=0;j<sz;j++)
6965 int nodeId(conn[*connI+1+j]);
6966 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
6968 if(!cm.isQuadratic())
6969 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
6971 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
6972 INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
6973 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
6979 * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
6980 * useful for 2D meshes having quadratic cells
6981 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
6982 * the two extremities of the arc of circle).
6984 * \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)
6985 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6986 * \throw If \a this is not fully defined.
6987 * \throw If \a this is not a mesh with meshDimension equal to 1.
6988 * \throw If \a this is not a mesh with spaceDimension equal to 2.
6989 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
6991 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
6993 checkFullyDefined();
6994 int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
6995 if(spaceDim!=2 || mDim!=1)
6996 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!");
6997 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6998 double *bbox(ret->getPointer());
6999 const double *coords(_coords->begin());
7000 const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
7001 for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
7003 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
7004 int sz(connI[1]-connI[0]-1);
7005 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=arcDetEps;
7006 std::vector<INTERP_KERNEL::Node *> nodes(sz);
7007 INTERP_KERNEL::Edge *edge(0);
7008 for(int j=0;j<sz;j++)
7010 int nodeId(conn[*connI+1+j]);
7011 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
7013 if(!cm.isQuadratic())
7014 edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
7016 edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
7017 const INTERP_KERNEL::Bounds& b(edge->getBounds());
7018 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
7025 namespace MEDCouplingImpl
7030 ConnReader(const int *c, int val):_conn(c),_val(val) { }
7031 bool operator() (const int& pos) { return _conn[pos]!=_val; }
7040 ConnReader2(const int *c, int val):_conn(c),_val(val) { }
7041 bool operator() (const int& pos) { return _conn[pos]==_val; }
7051 * This method expects that \a this is sorted by types. If not an exception will be thrown.
7052 * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
7053 * \a this is composed in cell types.
7054 * The returned array is of size 3*n where n is the number of different types present in \a this.
7055 * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
7056 * This parameter is kept only for compatibility with other methode listed above.
7058 std::vector<int> MEDCouplingUMesh::getDistributionOfTypes() const
7060 checkConnectivityFullyDefined();
7061 const int *conn=_nodal_connec->begin();
7062 const int *connI=_nodal_connec_index->begin();
7063 const int *work=connI;
7064 int nbOfCells=getNumberOfCells();
7065 std::size_t n=getAllGeoTypes().size();
7066 std::vector<int> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
7067 std::set<INTERP_KERNEL::NormalizedCellType> types;
7068 for(std::size_t i=0;work!=connI+nbOfCells;i++)
7070 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
7071 if(types.find(typ)!=types.end())
7073 std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
7074 oss << " is not contiguous !";
7075 throw INTERP_KERNEL::Exception(oss.str());
7079 const int *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
7080 ret[3*i+1]=(int)std::distance(work,work2);
7087 * This method is used to check that this has contiguous cell type in same order than described in \a code.
7088 * only for types cell, type node is not managed.
7089 * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
7090 * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
7091 * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
7092 * If 2 or more same geometric type is in \a code and exception is thrown too.
7094 * This method firstly checks
7095 * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
7096 * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
7097 * an exception is thrown too.
7099 * If all geometric types in \a code are exactly those in \a this null pointer is returned.
7100 * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
7101 * and a DataArrayInt instance is returned that the user has the responsability to deallocate.
7103 DataArrayInt *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<int>& code, const std::vector<const DataArrayInt *>& idsPerType) const
7106 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
7107 std::size_t sz=code.size();
7110 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
7111 std::vector<INTERP_KERNEL::NormalizedCellType> types;
7113 bool isNoPflUsed=true;
7114 for(std::size_t i=0;i<n;i++)
7115 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
7117 types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
7119 if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
7120 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
7121 isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
7124 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
7127 if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
7128 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
7129 if(types.size()==_types.size())
7132 MCAuto<DataArrayInt> ret=DataArrayInt::New();
7134 int *retPtr=ret->getPointer();
7135 const int *connI=_nodal_connec_index->begin();
7136 const int *conn=_nodal_connec->begin();
7137 int nbOfCells=getNumberOfCells();
7140 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
7142 i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,(int)(*it)));
7143 int offset=(int)std::distance(connI,i);
7144 const int *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)(*it)));
7145 int nbOfCellsOfCurType=(int)std::distance(i,j);
7146 if(code[3*kk+2]==-1)
7147 for(int k=0;k<nbOfCellsOfCurType;k++)
7151 int idInIdsPerType=code[3*kk+2];
7152 if(idInIdsPerType>=0 && idInIdsPerType<(int)idsPerType.size())
7154 const DataArrayInt *zePfl=idsPerType[idInIdsPerType];
7157 zePfl->checkAllocated();
7158 if(zePfl->getNumberOfComponents()==1)
7160 for(const int *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
7162 if(*k>=0 && *k<nbOfCellsOfCurType)
7163 *retPtr=(*k)+offset;
7166 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
7167 oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
7168 throw INTERP_KERNEL::Exception(oss.str());
7173 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
7176 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
7180 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
7181 oss << " should be in [0," << idsPerType.size() << ") !";
7182 throw INTERP_KERNEL::Exception(oss.str());
7191 * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
7192 * 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.
7193 * 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.
7194 * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
7196 * \param [in] profile
7197 * \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.
7198 * \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,
7199 * \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
7200 * \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.
7201 * This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
7202 * \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
7204 void MEDCouplingUMesh::splitProfilePerType(const DataArrayInt *profile, std::vector<int>& code, std::vector<DataArrayInt *>& idsInPflPerType, std::vector<DataArrayInt *>& idsPerType) const
7207 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
7208 if(profile->getNumberOfComponents()!=1)
7209 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
7210 checkConnectivityFullyDefined();
7211 const int *conn=_nodal_connec->begin();
7212 const int *connI=_nodal_connec_index->begin();
7213 int nbOfCells=getNumberOfCells();
7214 std::vector<INTERP_KERNEL::NormalizedCellType> types;
7215 std::vector<int> typeRangeVals(1);
7216 for(const int *i=connI;i!=connI+nbOfCells;)
7218 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7219 if(std::find(types.begin(),types.end(),curType)!=types.end())
7221 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
7223 types.push_back(curType);
7224 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7225 typeRangeVals.push_back((int)std::distance(connI,i));
7228 DataArrayInt *castArr=0,*rankInsideCast=0,*castsPresent=0;
7229 profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
7230 MCAuto<DataArrayInt> tmp0=castArr;
7231 MCAuto<DataArrayInt> tmp1=rankInsideCast;
7232 MCAuto<DataArrayInt> tmp2=castsPresent;
7234 int nbOfCastsFinal=castsPresent->getNumberOfTuples();
7235 code.resize(3*nbOfCastsFinal);
7236 std::vector< MCAuto<DataArrayInt> > idsInPflPerType2;
7237 std::vector< MCAuto<DataArrayInt> > idsPerType2;
7238 for(int i=0;i<nbOfCastsFinal;i++)
7240 int castId=castsPresent->getIJ(i,0);
7241 MCAuto<DataArrayInt> tmp3=castArr->findIdsEqual(castId);
7242 idsInPflPerType2.push_back(tmp3);
7243 code[3*i]=(int)types[castId];
7244 code[3*i+1]=tmp3->getNumberOfTuples();
7245 MCAuto<DataArrayInt> tmp4=rankInsideCast->selectByTupleId(tmp3->begin(),tmp3->begin()+tmp3->getNumberOfTuples());
7246 if(!tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
7248 tmp4->copyStringInfoFrom(*profile);
7249 idsPerType2.push_back(tmp4);
7250 code[3*i+2]=(int)idsPerType2.size()-1;
7257 std::size_t sz2=idsInPflPerType2.size();
7258 idsInPflPerType.resize(sz2);
7259 for(std::size_t i=0;i<sz2;i++)
7261 DataArrayInt *locDa=idsInPflPerType2[i];
7263 idsInPflPerType[i]=locDa;
7265 std::size_t sz=idsPerType2.size();
7266 idsPerType.resize(sz);
7267 for(std::size_t i=0;i<sz;i++)
7269 DataArrayInt *locDa=idsPerType2[i];
7271 idsPerType[i]=locDa;
7276 * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
7277 * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
7278 * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
7279 * 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.
7281 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *&revDesc, DataArrayInt *&revDescIndx, DataArrayInt *& nM1LevMeshIds, DataArrayInt *&meshnM1Old2New) const
7283 checkFullyDefined();
7284 nM1LevMesh->checkFullyDefined();
7285 if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
7286 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
7287 if(_coords!=nM1LevMesh->getCoords())
7288 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
7289 MCAuto<DataArrayInt> tmp0=DataArrayInt::New();
7290 MCAuto<DataArrayInt> tmp1=DataArrayInt::New();
7291 MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
7292 MCAuto<DataArrayInt> ret0=ret1->sortCellsInMEDFileFrmt();
7293 desc->transformWithIndArr(ret0->begin(),ret0->begin()+ret0->getNbOfElems());
7294 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
7295 tmp->setConnectivity(tmp0,tmp1);
7296 tmp->renumberCells(ret0->begin(),false);
7297 revDesc=tmp->getNodalConnectivity();
7298 revDescIndx=tmp->getNodalConnectivityIndex();
7299 DataArrayInt *ret=0;
7300 if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
7303 ret->getMaxValue(tmp2);
7305 std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
7306 throw INTERP_KERNEL::Exception(oss.str());
7311 revDescIndx->incrRef();
7314 meshnM1Old2New=ret0;
7319 * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
7320 * necessary for writing the mesh to MED file. Additionally returns a permutation array
7321 * in "Old to New" mode.
7322 * \return DataArrayInt * - a new instance of DataArrayInt. The caller is to delete
7323 * this array using decrRef() as it is no more needed.
7324 * \throw If the nodal connectivity of cells is not defined.
7326 DataArrayInt *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
7328 checkConnectivityFullyDefined();
7329 MCAuto<DataArrayInt> ret=getRenumArrForMEDFileFrmt();
7330 renumberCells(ret->begin(),false);
7335 * This methods checks that cells are sorted by their types.
7336 * This method makes asumption (no check) that connectivity is correctly set before calling.
7338 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
7340 checkFullyDefined();
7341 const int *conn=_nodal_connec->begin();
7342 const int *connI=_nodal_connec_index->begin();
7343 int nbOfCells=getNumberOfCells();
7344 std::set<INTERP_KERNEL::NormalizedCellType> types;
7345 for(const int *i=connI;i!=connI+nbOfCells;)
7347 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7348 if(types.find(curType)!=types.end())
7350 types.insert(curType);
7351 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7357 * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
7358 * The geometric type order is specified by MED file.
7360 * \sa MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
7362 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
7364 return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
7368 * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
7369 * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
7370 * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
7371 * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
7373 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
7375 checkFullyDefined();
7376 const int *conn=_nodal_connec->begin();
7377 const int *connI=_nodal_connec_index->begin();
7378 int nbOfCells=getNumberOfCells();
7382 std::set<INTERP_KERNEL::NormalizedCellType> sg;
7383 for(const int *i=connI;i!=connI+nbOfCells;)
7385 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7386 const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
7387 if(isTypeExists!=orderEnd)
7389 int pos=(int)std::distance(orderBg,isTypeExists);
7393 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7397 if(sg.find(curType)==sg.end())
7399 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7410 * This method returns 2 newly allocated DataArrayInt instances. The first is an array of size 'this->getNumberOfCells()' with one component,
7411 * 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
7412 * 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'.
7414 DataArrayInt *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayInt *&nbPerType) const
7416 checkConnectivityFullyDefined();
7417 int nbOfCells=getNumberOfCells();
7418 const int *conn=_nodal_connec->begin();
7419 const int *connI=_nodal_connec_index->begin();
7420 MCAuto<DataArrayInt> tmpa=DataArrayInt::New();
7421 MCAuto<DataArrayInt> tmpb=DataArrayInt::New();
7422 tmpa->alloc(nbOfCells,1);
7423 tmpb->alloc((int)std::distance(orderBg,orderEnd),1);
7424 tmpb->fillWithZero();
7425 int *tmp=tmpa->getPointer();
7426 int *tmp2=tmpb->getPointer();
7427 for(const int *i=connI;i!=connI+nbOfCells;i++)
7429 const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
7432 int pos=(int)std::distance(orderBg,where);
7434 tmp[std::distance(connI,i)]=pos;
7438 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
7439 std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
7440 oss << " has a type " << cm.getRepr() << " not in input array of type !";
7441 throw INTERP_KERNEL::Exception(oss.str());
7444 nbPerType=tmpb.retn();
7449 * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
7451 * \return a new object containing the old to new correspondance.
7453 * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
7455 DataArrayInt *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
7457 return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
7461 * 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.
7462 * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
7463 * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
7464 * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
7466 DataArrayInt *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
7468 DataArrayInt *nbPerType=0;
7469 MCAuto<DataArrayInt> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
7470 nbPerType->decrRef();
7471 return tmpa->buildPermArrPerLevel();
7475 * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
7476 * The number of cells remains unchanged after the call of this method.
7477 * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
7478 * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
7480 * \return the array giving the correspondance old to new.
7482 DataArrayInt *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
7484 checkFullyDefined();
7486 const int *conn=_nodal_connec->begin();
7487 const int *connI=_nodal_connec_index->begin();
7488 int nbOfCells=getNumberOfCells();
7489 std::vector<INTERP_KERNEL::NormalizedCellType> types;
7490 for(const int *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
7491 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
7493 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7494 types.push_back(curType);
7495 for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
7497 DataArrayInt *ret=DataArrayInt::New();
7498 ret->alloc(nbOfCells,1);
7499 int *retPtr=ret->getPointer();
7500 std::fill(retPtr,retPtr+nbOfCells,-1);
7502 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
7504 for(const int *i=connI;i!=connI+nbOfCells;i++)
7505 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
7506 retPtr[std::distance(connI,i)]=newCellId++;
7508 renumberCells(retPtr,false);
7513 * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
7514 * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
7515 * This method makes asumption that connectivity is correctly set before calling.
7517 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
7519 checkConnectivityFullyDefined();
7520 const int *conn=_nodal_connec->begin();
7521 const int *connI=_nodal_connec_index->begin();
7522 int nbOfCells=getNumberOfCells();
7523 std::vector<MEDCouplingUMesh *> ret;
7524 for(const int *i=connI;i!=connI+nbOfCells;)
7526 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7527 int beginCellId=(int)std::distance(connI,i);
7528 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7529 int endCellId=(int)std::distance(connI,i);
7530 int sz=endCellId-beginCellId;
7531 int *cells=new int[sz];
7532 for(int j=0;j<sz;j++)
7533 cells[j]=beginCellId+j;
7534 MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
7542 * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
7543 * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
7544 * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
7546 * \return a newly allocated instance, that the caller must manage.
7547 * \throw If \a this contains more than one geometric type.
7548 * \throw If the nodal connectivity of \a this is not fully defined.
7549 * \throw If the internal data is not coherent.
7551 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
7553 checkConnectivityFullyDefined();
7554 if(_types.size()!=1)
7555 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7556 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
7557 MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
7558 ret->setCoords(getCoords());
7559 MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
7562 MCAuto<DataArrayInt> c=convertNodalConnectivityToStaticGeoTypeMesh();
7563 retC->setNodalConnectivity(c);
7567 MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
7569 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
7570 DataArrayInt *c=0,*ci=0;
7571 convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
7572 MCAuto<DataArrayInt> cs(c),cis(ci);
7573 retD->setNodalConnectivity(cs,cis);
7578 DataArrayInt *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
7580 checkConnectivityFullyDefined();
7581 if(_types.size()!=1)
7582 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7583 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
7584 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
7587 std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
7588 oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
7589 throw INTERP_KERNEL::Exception(oss.str());
7591 int nbCells=getNumberOfCells();
7593 int nbNodesPerCell=(int)cm.getNumberOfNodes();
7594 MCAuto<DataArrayInt> connOut=DataArrayInt::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
7595 int *outPtr=connOut->getPointer();
7596 const int *conn=_nodal_connec->begin();
7597 const int *connI=_nodal_connec_index->begin();
7599 for(int i=0;i<nbCells;i++,connI++)
7601 if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
7602 outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
7605 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 << ") !";
7606 throw INTERP_KERNEL::Exception(oss.str());
7609 return connOut.retn();
7613 * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
7614 * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
7618 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayInt *&nodalConn, DataArrayInt *&nodalConnIndex) const
7620 static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
7621 checkConnectivityFullyDefined();
7622 if(_types.size()!=1)
7623 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7624 int nbCells=getNumberOfCells(),lgth=_nodal_connec->getNumberOfTuples();
7626 throw INTERP_KERNEL::Exception(msg0);
7627 MCAuto<DataArrayInt> c(DataArrayInt::New()),ci(DataArrayInt::New());
7628 c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
7629 int *cp(c->getPointer()),*cip(ci->getPointer());
7630 const int *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
7632 for(int i=0;i<nbCells;i++,cip++,incip++)
7634 int strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
7635 int delta(stop-strt);
7638 if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
7639 cp=std::copy(incp+strt,incp+stop,cp);
7641 throw INTERP_KERNEL::Exception(msg0);
7644 throw INTERP_KERNEL::Exception(msg0);
7645 cip[1]=cip[0]+delta;
7647 nodalConn=c.retn(); nodalConnIndex=ci.retn();
7651 * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
7652 * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
7653 * This method is particulary useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
7654 * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
7655 * are not used here to avoid the build of big permutation array.
7657 * \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
7658 * those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
7659 * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayInt instance whose number of tuples is equal to the number of chunks of same geotype
7660 * in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
7661 * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayInt instance having the same size than \b szOfCellGrpOfSameType. This
7662 * output array gives for each chunck of same type the corresponding mesh id in \b ms.
7663 * \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
7664 * is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
7666 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
7667 DataArrayInt *&szOfCellGrpOfSameType,
7668 DataArrayInt *&idInMsOfCellGrpOfSameType)
7670 std::vector<const MEDCouplingUMesh *> ms2;
7671 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
7674 (*it)->checkConnectivityFullyDefined();
7678 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
7679 const DataArrayDouble *refCoo=ms2[0]->getCoords();
7680 int meshDim=ms2[0]->getMeshDimension();
7681 std::vector<const MEDCouplingUMesh *> m1ssm;
7682 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
7684 std::vector<const MEDCouplingUMesh *> m1ssmSingle;
7685 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
7687 MCAuto<DataArrayInt> ret1(DataArrayInt::New()),ret2(DataArrayInt::New());
7688 ret1->alloc(0,1); ret2->alloc(0,1);
7689 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
7691 if(meshDim!=(*it)->getMeshDimension())
7692 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
7693 if(refCoo!=(*it)->getCoords())
7694 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
7695 std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
7696 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
7697 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
7698 for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
7700 MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
7701 m1ssmSingleAuto.push_back(singleCell);
7702 m1ssmSingle.push_back(singleCell);
7703 ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
7706 MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
7707 MCAuto<DataArrayInt> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
7708 std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
7709 for(std::size_t i=0;i<m1ssm.size();i++)
7710 m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
7711 MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
7712 szOfCellGrpOfSameType=ret1->renumber(renum->begin());
7713 idInMsOfCellGrpOfSameType=ret2->renumber(renum->begin());
7718 * This method returns a newly created DataArrayInt instance.
7719 * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
7721 DataArrayInt *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const int *begin, const int *end) const
7723 checkFullyDefined();
7724 const int *conn=_nodal_connec->begin();
7725 const int *connIndex=_nodal_connec_index->begin();
7726 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
7727 for(const int *w=begin;w!=end;w++)
7728 if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
7729 ret->pushBackSilent(*w);
7734 * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
7735 * are in [0:getNumberOfCells())
7737 DataArrayInt *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayInt *da) const
7739 checkFullyDefined();
7740 const int *conn=_nodal_connec->begin();
7741 const int *connI=_nodal_connec_index->begin();
7742 int nbOfCells=getNumberOfCells();
7743 std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
7744 int *tmp=new int[nbOfCells];
7745 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
7748 for(const int *i=connI;i!=connI+nbOfCells;i++)
7749 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
7750 tmp[std::distance(connI,i)]=j++;
7752 DataArrayInt *ret=DataArrayInt::New();
7753 ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
7754 ret->copyStringInfoFrom(*da);
7755 int *retPtr=ret->getPointer();
7756 const int *daPtr=da->begin();
7757 int nbOfElems=da->getNbOfElems();
7758 for(int k=0;k<nbOfElems;k++)
7759 retPtr[k]=tmp[daPtr[k]];
7765 * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
7766 * This method \b works \b for mesh sorted by type.
7767 * cells whose ids is in 'idsPerGeoType' array.
7768 * This method conserves coords and name of mesh.
7770 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const int *idsPerGeoTypeBg, const int *idsPerGeoTypeEnd) const
7772 std::vector<int> code=getDistributionOfTypes();
7773 std::size_t nOfTypesInThis=code.size()/3;
7774 int sz=0,szOfType=0;
7775 for(std::size_t i=0;i<nOfTypesInThis;i++)
7780 szOfType=code[3*i+1];
7782 for(const int *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
7783 if(*work<0 || *work>=szOfType)
7785 std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
7786 oss << ". It should be in [0," << szOfType << ") !";
7787 throw INTERP_KERNEL::Exception(oss.str());
7789 MCAuto<DataArrayInt> idsTokeep=DataArrayInt::New(); idsTokeep->alloc(sz+(int)std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
7790 int *idsPtr=idsTokeep->getPointer();
7792 for(std::size_t i=0;i<nOfTypesInThis;i++)
7795 for(int j=0;j<code[3*i+1];j++)
7798 idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind2nd(std::plus<int>(),offset));
7799 offset+=code[3*i+1];
7801 MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
7802 ret->copyTinyInfoFrom(this);
7807 * This method returns a vector of size 'this->getNumberOfCells()'.
7808 * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
7810 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
7812 int ncell=getNumberOfCells();
7813 std::vector<bool> ret(ncell);
7814 const int *cI=getNodalConnectivityIndex()->begin();
7815 const int *c=getNodalConnectivity()->begin();
7816 for(int i=0;i<ncell;i++)
7818 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
7819 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
7820 ret[i]=cm.isQuadratic();
7826 * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
7828 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
7830 if(other->getType()!=UNSTRUCTURED)
7831 throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
7832 const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
7833 return MergeUMeshes(this,otherC);
7837 * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
7838 * computed by averaging coordinates of cell nodes, so this method is not a right
7839 * choice for degnerated meshes (not well oriented, cells with measure close to zero).
7840 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
7841 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
7842 * components. The caller is to delete this array using decrRef() as it is
7844 * \throw If the coordinates array is not set.
7845 * \throw If the nodal connectivity of cells is not defined.
7846 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
7848 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
7850 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
7851 int spaceDim=getSpaceDimension();
7852 int nbOfCells=getNumberOfCells();
7853 ret->alloc(nbOfCells,spaceDim);
7854 ret->copyStringInfoFrom(*getCoords());
7855 double *ptToFill=ret->getPointer();
7856 const int *nodal=_nodal_connec->begin();
7857 const int *nodalI=_nodal_connec_index->begin();
7858 const double *coor=_coords->begin();
7859 for(int i=0;i<nbOfCells;i++)
7861 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
7862 INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
7869 * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
7870 * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
7872 * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
7873 * DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
7875 * \sa MEDCouplingUMesh::computeCellCenterOfMass
7876 * \throw If \a this is not fully defined (coordinates and connectivity)
7877 * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
7879 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
7881 checkFullyDefined();
7882 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
7883 int spaceDim=getSpaceDimension();
7884 int nbOfCells=getNumberOfCells();
7885 int nbOfNodes=getNumberOfNodes();
7886 ret->alloc(nbOfCells,spaceDim);
7887 double *ptToFill=ret->getPointer();
7888 const int *nodal=_nodal_connec->begin();
7889 const int *nodalI=_nodal_connec_index->begin();
7890 const double *coor=_coords->begin();
7891 for(int i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
7893 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
7894 std::fill(ptToFill,ptToFill+spaceDim,0.);
7895 if(type!=INTERP_KERNEL::NORM_POLYHED)
7897 for(const int *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
7899 if(*conn>=0 && *conn<nbOfNodes)
7900 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
7903 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," << nbOfNodes << ") !";
7904 throw INTERP_KERNEL::Exception(oss.str());
7907 int nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
7908 if(nbOfNodesInCell>0)
7909 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
7912 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
7913 throw INTERP_KERNEL::Exception(oss.str());
7918 std::set<int> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
7920 for(std::set<int>::const_iterator it=s.begin();it!=s.end();it++)
7922 if(*it>=0 && *it<nbOfNodes)
7923 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
7926 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," << nbOfNodes << ") !";
7927 throw INTERP_KERNEL::Exception(oss.str());
7931 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)s.size()));
7934 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
7935 throw INTERP_KERNEL::Exception(oss.str());
7943 * Returns a new DataArrayDouble holding barycenters of specified cells. The
7944 * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
7945 * are specified via an array of cell ids.
7946 * \warning Validity of the specified cell ids is not checked!
7947 * Valid range is [ 0, \a this->getNumberOfCells() ).
7948 * \param [in] begin - an array of cell ids of interest.
7949 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
7950 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
7951 * end - \a begin ) tuples per \a this->getSpaceDimension() components. The
7952 * caller is to delete this array using decrRef() as it is no more needed.
7953 * \throw If the coordinates array is not set.
7954 * \throw If the nodal connectivity of cells is not defined.
7956 * \if ENABLE_EXAMPLES
7957 * \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
7958 * \ref py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
7961 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const int *begin, const int *end) const
7963 DataArrayDouble *ret=DataArrayDouble::New();
7964 int spaceDim=getSpaceDimension();
7965 int nbOfTuple=(int)std::distance(begin,end);
7966 ret->alloc(nbOfTuple,spaceDim);
7967 double *ptToFill=ret->getPointer();
7968 double *tmp=new double[spaceDim];
7969 const int *nodal=_nodal_connec->begin();
7970 const int *nodalI=_nodal_connec_index->begin();
7971 const double *coor=_coords->begin();
7972 for(const int *w=begin;w!=end;w++)
7974 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
7975 INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
7983 * 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".
7984 * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
7985 * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
7986 * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
7987 * This method is useful to detect 2D cells in 3D space that are not coplanar.
7989 * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
7990 * \throw If spaceDim!=3 or meshDim!=2.
7991 * \throw If connectivity of \a this is invalid.
7992 * \throw If connectivity of a cell in \a this points to an invalid node.
7994 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
7996 MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
7997 int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
7998 if(getSpaceDimension()!=3 || getMeshDimension()!=2)
7999 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
8000 ret->alloc(nbOfCells,4);
8001 double *retPtr(ret->getPointer());
8002 const int *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
8003 const double *coor(_coords->begin());
8004 for(int i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
8006 double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
8007 if(nodalI[1]-nodalI[0]>=3)
8009 for(int j=0;j<3;j++)
8011 int nodeId(nodal[nodalI[0]+1+j]);
8012 if(nodeId>=0 && nodeId<nbOfNodes)
8013 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
8016 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
8017 throw INTERP_KERNEL::Exception(oss.str());
8023 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
8024 throw INTERP_KERNEL::Exception(oss.str());
8026 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
8027 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
8033 * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
8036 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
8039 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
8040 da->checkAllocated();
8041 std::string name(da->getName());
8042 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(name,0));
8044 ret->setName("Mesh");
8046 int nbOfTuples(da->getNumberOfTuples());
8047 MCAuto<DataArrayInt> c(DataArrayInt::New()),cI(DataArrayInt::New());
8048 c->alloc(2*nbOfTuples,1);
8049 cI->alloc(nbOfTuples+1,1);
8050 int *cp(c->getPointer()),*cip(cI->getPointer());
8052 for(int i=0;i<nbOfTuples;i++)
8054 *cp++=INTERP_KERNEL::NORM_POINT1;
8058 ret->setConnectivity(c,cI,true);
8062 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::Build1DMeshFromCoords(DataArrayDouble *da)
8065 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build01MeshFromCoords : instance of DataArrayDouble must be not null !");
8066 da->checkAllocated();
8067 std::string name(da->getName());
8068 MCAuto<MEDCouplingUMesh> ret;
8070 MCAuto<MEDCouplingCMesh> tmp(MEDCouplingCMesh::New());
8071 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
8072 arr->alloc(da->getNumberOfTuples());
8073 tmp->setCoordsAt(0,arr);
8074 ret=tmp->buildUnstructured();
8078 ret->setName("Mesh");
8085 * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
8086 * Cells and nodes of
8087 * the first mesh precede cells and nodes of the second mesh within the result mesh.
8088 * \param [in] mesh1 - the first mesh.
8089 * \param [in] mesh2 - the second mesh.
8090 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8091 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8092 * is no more needed.
8093 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
8094 * \throw If the coordinates array is not set in none of the meshes.
8095 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
8096 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
8098 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
8100 std::vector<const MEDCouplingUMesh *> tmp(2);
8101 tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
8102 return MergeUMeshes(tmp);
8106 * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
8107 * Cells and nodes of
8108 * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
8109 * \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
8110 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8111 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8112 * is no more needed.
8113 * \throw If \a a.size() == 0.
8114 * \throw If \a a[ *i* ] == NULL.
8115 * \throw If the coordinates array is not set in none of the meshes.
8116 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
8117 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
8119 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const std::vector<const MEDCouplingUMesh *>& a)
8121 std::size_t sz=a.size();
8123 return MergeUMeshesLL(a);
8124 for(std::size_t ii=0;ii<sz;ii++)
8127 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
8128 throw INTERP_KERNEL::Exception(oss.str());
8130 std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
8131 std::vector< const MEDCouplingUMesh * > aa(sz);
8133 for(std::size_t i=0;i<sz && spaceDim==-3;i++)
8135 const MEDCouplingUMesh *cur=a[i];
8136 const DataArrayDouble *coo=cur->getCoords();
8138 spaceDim=coo->getNumberOfComponents();
8141 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
8142 for(std::size_t i=0;i<sz;i++)
8144 bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
8147 return MergeUMeshesLL(aa);
8152 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesLL(const std::vector<const MEDCouplingUMesh *>& a)
8155 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : input array must be NON EMPTY !");
8156 std::vector<const MEDCouplingUMesh *>::const_iterator it=a.begin();
8157 int meshDim=(*it)->getMeshDimension();
8158 int nbOfCells=(*it)->getNumberOfCells();
8159 int meshLgth=(*it++)->getNodalConnectivityArrayLen();
8160 for(;it!=a.end();it++)
8162 if(meshDim!=(*it)->getMeshDimension())
8163 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, MergeUMeshes impossible !");
8164 nbOfCells+=(*it)->getNumberOfCells();
8165 meshLgth+=(*it)->getNodalConnectivityArrayLen();
8167 std::vector<const MEDCouplingPointSet *> aps(a.size());
8168 std::copy(a.begin(),a.end(),aps.begin());
8169 MCAuto<DataArrayDouble> pts=MergeNodesArray(aps);
8170 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("merge",meshDim);
8171 ret->setCoords(pts);
8172 MCAuto<DataArrayInt> c=DataArrayInt::New();
8173 c->alloc(meshLgth,1);
8174 int *cPtr=c->getPointer();
8175 MCAuto<DataArrayInt> cI=DataArrayInt::New();
8176 cI->alloc(nbOfCells+1,1);
8177 int *cIPtr=cI->getPointer();
8181 for(it=a.begin();it!=a.end();it++)
8183 int curNbOfCell=(*it)->getNumberOfCells();
8184 const int *curCI=(*it)->_nodal_connec_index->begin();
8185 const int *curC=(*it)->_nodal_connec->begin();
8186 cIPtr=std::transform(curCI+1,curCI+curNbOfCell+1,cIPtr,std::bind2nd(std::plus<int>(),offset));
8187 for(int j=0;j<curNbOfCell;j++)
8189 const int *src=curC+curCI[j];
8191 for(;src!=curC+curCI[j+1];src++,cPtr++)
8199 offset+=curCI[curNbOfCell];
8200 offset2+=(*it)->getNumberOfNodes();
8203 ret->setConnectivity(c,cI,true);
8210 * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
8211 * dimension and sharing the node coordinates array.
8212 * All cells of the first mesh precede all cells of the second mesh
8213 * within the result mesh.
8214 * \param [in] mesh1 - the first mesh.
8215 * \param [in] mesh2 - the second mesh.
8216 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8217 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8218 * is no more needed.
8219 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
8220 * \throw If the meshes do not share the node coordinates array.
8221 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
8222 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
8224 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
8226 std::vector<const MEDCouplingUMesh *> tmp(2);
8227 tmp[0]=mesh1; tmp[1]=mesh2;
8228 return MergeUMeshesOnSameCoords(tmp);
8232 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
8233 * dimension and sharing the node coordinates array.
8234 * All cells of the *i*-th mesh precede all cells of the
8235 * (*i*+1)-th mesh within the result mesh.
8236 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
8237 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8238 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8239 * is no more needed.
8240 * \throw If \a a.size() == 0.
8241 * \throw If \a a[ *i* ] == NULL.
8242 * \throw If the meshes do not share the node coordinates array.
8243 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
8244 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
8246 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
8249 throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
8250 for(std::size_t ii=0;ii<meshes.size();ii++)
8253 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
8254 throw INTERP_KERNEL::Exception(oss.str());
8256 const DataArrayDouble *coords=meshes.front()->getCoords();
8257 int meshDim=meshes.front()->getMeshDimension();
8258 std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
8260 int meshIndexLgth=0;
8261 for(;iter!=meshes.end();iter++)
8263 if(coords!=(*iter)->getCoords())
8264 throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
8265 if(meshDim!=(*iter)->getMeshDimension())
8266 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
8267 meshLgth+=(*iter)->getNodalConnectivityArrayLen();
8268 meshIndexLgth+=(*iter)->getNumberOfCells();
8270 MCAuto<DataArrayInt> nodal=DataArrayInt::New();
8271 nodal->alloc(meshLgth,1);
8272 int *nodalPtr=nodal->getPointer();
8273 MCAuto<DataArrayInt> nodalIndex=DataArrayInt::New();
8274 nodalIndex->alloc(meshIndexLgth+1,1);
8275 int *nodalIndexPtr=nodalIndex->getPointer();
8277 for(iter=meshes.begin();iter!=meshes.end();iter++)
8279 const int *nod=(*iter)->getNodalConnectivity()->begin();
8280 const int *index=(*iter)->getNodalConnectivityIndex()->begin();
8281 int nbOfCells=(*iter)->getNumberOfCells();
8282 int meshLgth2=(*iter)->getNodalConnectivityArrayLen();
8283 nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
8284 if(iter!=meshes.begin())
8285 nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind2nd(std::plus<int>(),offset));
8287 nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
8290 MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
8291 ret->setName("merge");
8292 ret->setMeshDimension(meshDim);
8293 ret->setConnectivity(nodal,nodalIndex,true);
8294 ret->setCoords(coords);
8299 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
8300 * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
8301 * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
8302 * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
8303 * New" mode are returned for each input mesh.
8304 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
8305 * \param [in] compType - specifies a cell comparison technique. For meaning of its
8306 * valid values [0,1,2], see zipConnectivityTraducer().
8307 * \param [in,out] corr - an array of DataArrayInt, of the same size as \a
8308 * meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
8309 * mesh. The caller is to delete each of the arrays using decrRef() as it is
8311 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8312 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8313 * is no more needed.
8314 * \throw If \a meshes.size() == 0.
8315 * \throw If \a meshes[ *i* ] == NULL.
8316 * \throw If the meshes do not share the node coordinates array.
8317 * \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
8318 * \throw If the \a meshes are of different dimension (getMeshDimension()).
8319 * \throw If the nodal connectivity of cells of any of \a meshes is not defined.
8320 * \throw If the nodal connectivity any of \a meshes includes an invalid id.
8322 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayInt *>& corr)
8324 //All checks are delegated to MergeUMeshesOnSameCoords
8325 MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
8326 MCAuto<DataArrayInt> o2n=ret->zipConnectivityTraducer(compType);
8327 corr.resize(meshes.size());
8328 std::size_t nbOfMeshes=meshes.size();
8330 const int *o2nPtr=o2n->begin();
8331 for(std::size_t i=0;i<nbOfMeshes;i++)
8333 DataArrayInt *tmp=DataArrayInt::New();
8334 int curNbOfCells=meshes[i]->getNumberOfCells();
8335 tmp->alloc(curNbOfCells,1);
8336 std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
8337 offset+=curNbOfCells;
8338 tmp->setName(meshes[i]->getName());
8345 * Makes all given meshes share the nodal connectivity array. The common connectivity
8346 * array is created by concatenating the connectivity arrays of all given meshes. All
8347 * the given meshes must be of the same space dimension but dimension of cells **can
8348 * differ**. This method is particulary useful in MEDLoader context to build a \ref
8349 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
8350 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
8351 * \param [in,out] meshes - a vector of meshes to update.
8352 * \throw If any of \a meshes is NULL.
8353 * \throw If the coordinates array is not set in any of \a meshes.
8354 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
8355 * \throw If \a meshes are of different space dimension.
8357 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
8359 std::size_t sz=meshes.size();
8362 std::vector< const DataArrayDouble * > coords(meshes.size());
8363 std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
8364 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
8368 (*it)->checkConnectivityFullyDefined();
8369 const DataArrayDouble *coo=(*it)->getCoords();
8374 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
8375 oss << " has no coordinate array defined !";
8376 throw INTERP_KERNEL::Exception(oss.str());
8381 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
8382 oss << " is null !";
8383 throw INTERP_KERNEL::Exception(oss.str());
8386 MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
8387 std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
8388 int offset=(*it)->getNumberOfNodes();
8389 (*it++)->setCoords(res);
8390 for(;it!=meshes.end();it++)
8392 int oldNumberOfNodes=(*it)->getNumberOfNodes();
8393 (*it)->setCoords(res);
8394 (*it)->shiftNodeNumbersInConn(offset);
8395 offset+=oldNumberOfNodes;
8400 * Merges nodes coincident with a given precision within all given meshes that share
8401 * the nodal connectivity array. The given meshes **can be of different** mesh
8402 * dimension. This method is particulary useful in MEDLoader context to build a \ref
8403 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
8404 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
8405 * \param [in,out] meshes - a vector of meshes to update.
8406 * \param [in] eps - the precision used to detect coincident nodes (infinite norm).
8407 * \throw If any of \a meshes is NULL.
8408 * \throw If the \a meshes do not share the same node coordinates array.
8409 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
8411 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
8415 std::set<const DataArrayDouble *> s;
8416 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
8419 s.insert((*it)->getCoords());
8422 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 !";
8423 throw INTERP_KERNEL::Exception(oss.str());
8428 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 !";
8429 throw INTERP_KERNEL::Exception(oss.str());
8431 const DataArrayDouble *coo=*(s.begin());
8435 DataArrayInt *comm,*commI;
8436 coo->findCommonTuples(eps,-1,comm,commI);
8437 MCAuto<DataArrayInt> tmp1(comm),tmp2(commI);
8438 int oldNbOfNodes=coo->getNumberOfTuples();
8440 MCAuto<DataArrayInt> o2n=DataArrayInt::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
8441 if(oldNbOfNodes==newNbOfNodes)
8443 MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->begin(),newNbOfNodes);
8444 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
8446 (*it)->renumberNodesInConn(o2n->begin());
8447 (*it)->setCoords(newCoords);
8452 * 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.
8453 * \param nbOfNodesPerLev in parameter that specifies the number of nodes of one slice of global dataset
8454 * \param isQuad specifies the policy of connectivity.
8455 * @ret in/out parameter in which the result will be append
8457 void MEDCouplingUMesh::AppendExtrudedCell(const int *connBg, const int *connEnd, int nbOfNodesPerLev, bool isQuad, std::vector<int>& ret)
8459 INTERP_KERNEL::NormalizedCellType flatType=(INTERP_KERNEL::NormalizedCellType)connBg[0];
8460 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(flatType);
8461 ret.push_back(cm.getExtrudedType());
8462 int deltaz=isQuad?2*nbOfNodesPerLev:nbOfNodesPerLev;
8465 case INTERP_KERNEL::NORM_POINT1:
8467 ret.push_back(connBg[1]);
8468 ret.push_back(connBg[1]+nbOfNodesPerLev);
8471 case INTERP_KERNEL::NORM_SEG2:
8473 int conn[4]={connBg[1],connBg[2],connBg[2]+deltaz,connBg[1]+deltaz};
8474 ret.insert(ret.end(),conn,conn+4);
8477 case INTERP_KERNEL::NORM_SEG3:
8479 int conn[8]={connBg[1],connBg[3],connBg[3]+deltaz,connBg[1]+deltaz,connBg[2],connBg[3]+nbOfNodesPerLev,connBg[2]+deltaz,connBg[1]+nbOfNodesPerLev};
8480 ret.insert(ret.end(),conn,conn+8);
8483 case INTERP_KERNEL::NORM_QUAD4:
8485 int conn[8]={connBg[1],connBg[2],connBg[3],connBg[4],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4]+deltaz};
8486 ret.insert(ret.end(),conn,conn+8);
8489 case INTERP_KERNEL::NORM_TRI3:
8491 int conn[6]={connBg[1],connBg[2],connBg[3],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz};
8492 ret.insert(ret.end(),conn,conn+6);
8495 case INTERP_KERNEL::NORM_TRI6:
8497 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,
8498 connBg[1]+nbOfNodesPerLev,connBg[2]+nbOfNodesPerLev,connBg[3]+nbOfNodesPerLev};
8499 ret.insert(ret.end(),conn,conn+15);
8502 case INTERP_KERNEL::NORM_QUAD8:
8505 connBg[1],connBg[2],connBg[3],connBg[4],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4]+deltaz,
8506 connBg[5],connBg[6],connBg[7],connBg[8],connBg[5]+deltaz,connBg[6]+deltaz,connBg[7]+deltaz,connBg[8]+deltaz,
8507 connBg[1]+nbOfNodesPerLev,connBg[2]+nbOfNodesPerLev,connBg[3]+nbOfNodesPerLev,connBg[4]+nbOfNodesPerLev
8509 ret.insert(ret.end(),conn,conn+20);
8512 case INTERP_KERNEL::NORM_POLYGON:
8514 std::back_insert_iterator< std::vector<int> > ii(ret);
8515 std::copy(connBg+1,connEnd,ii);
8517 std::reverse_iterator<const int *> rConnBg(connEnd);
8518 std::reverse_iterator<const int *> rConnEnd(connBg+1);
8519 std::transform(rConnBg,rConnEnd,ii,std::bind2nd(std::plus<int>(),deltaz));
8520 std::size_t nbOfRadFaces=std::distance(connBg+1,connEnd);
8521 for(std::size_t i=0;i<nbOfRadFaces;i++)
8524 int conn[4]={connBg[(i+1)%nbOfRadFaces+1],connBg[i+1],connBg[i+1]+deltaz,connBg[(i+1)%nbOfRadFaces+1]+deltaz};
8525 std::copy(conn,conn+4,ii);
8530 throw INTERP_KERNEL::Exception("A flat type has been detected that has not its extruded representation !");
8535 * This static operates only for coords in 3D. The polygon is specfied by its connectivity nodes in [ \a begin , \a end ).
8537 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const int *begin, const int *end, const double *coords)
8540 double v[3]={0.,0.,0.};
8541 std::size_t sz=std::distance(begin,end);
8546 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];
8547 v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
8548 v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
8550 double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
8552 // Try using quadratic points if standard points are degenerated (for example a QPOLYG with two
8553 // SEG3 forming a circle):
8554 if (fabs(ret) < INTERP_KERNEL::DEFAULT_ABS_TOL && isQuadratic)
8556 v[0] = 0.0; v[1] = 0.0; v[2] = 0.0;
8557 for(std::size_t j=0;j<sz;j++)
8559 if (j%2) // current point i is quadratic, next point i+1 is standard
8562 ip1 = (j+1)%sz; // ip1 = "i+1"
8564 else // current point i is standard, next point i+1 is quadratic
8569 v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
8570 v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
8571 v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
8573 ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
8579 * The polyhedron is specfied by its connectivity nodes in [ \a begin , \a end ).
8581 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const int *begin, const int *end, const double *coords)
8583 std::vector<std::pair<int,int> > edges;
8584 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
8585 const int *bgFace=begin;
8586 for(std::size_t i=0;i<nbOfFaces;i++)
8588 const int *endFace=std::find(bgFace+1,end,-1);
8589 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
8590 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8592 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8593 if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
8595 edges.push_back(p1);
8599 return INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)>-EPS_FOR_POLYH_ORIENTATION;
8603 * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
8605 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const int *begin, const int *end, const double *coords)
8607 double vec0[3],vec1[3];
8608 std::size_t sz=std::distance(begin,end);
8610 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
8611 int nbOfNodes=(int)sz/2;
8612 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
8613 const double *pt0=coords+3*begin[0];
8614 const double *pt1=coords+3*begin[nbOfNodes];
8615 vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
8616 return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
8619 void MEDCouplingUMesh::CorrectExtrudedStaticCell(int *begin, int *end)
8621 std::size_t sz=std::distance(begin,end);
8622 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
8623 std::size_t nbOfNodes(sz/2);
8624 std::copy(begin,end,(int *)tmp);
8625 for(std::size_t j=1;j<nbOfNodes;j++)
8627 begin[j]=tmp[nbOfNodes-j];
8628 begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
8632 bool MEDCouplingUMesh::IsTetra4WellOriented(const int *begin, const int *end, const double *coords)
8634 std::size_t sz=std::distance(begin,end);
8636 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
8637 double vec0[3],vec1[3];
8638 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
8639 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];
8640 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;
8643 bool MEDCouplingUMesh::IsPyra5WellOriented(const int *begin, const int *end, const double *coords)
8645 std::size_t sz=std::distance(begin,end);
8647 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
8649 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
8650 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
8651 return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
8655 * 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 )
8656 * 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
8659 * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
8660 * \param [in] coords the coordinates with nb of components exactly equal to 3
8661 * \param [in] begin begin of the nodal connectivity (geometric type included) of a single polyhedron cell
8662 * \param [in] end end of nodal connectivity of a single polyhedron cell (excluded)
8663 * \param [out] res the result is put at the end of the vector without any alteration of the data.
8665 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, const int *begin, const int *end, DataArrayInt *res)
8667 int nbFaces=std::count(begin+1,end,-1)+1;
8668 MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
8669 double *vPtr=v->getPointer();
8670 MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,1);
8671 double *pPtr=p->getPointer();
8672 const int *stFaceConn=begin+1;
8673 for(int i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
8675 const int *endFaceConn=std::find(stFaceConn,end,-1);
8676 ComputeVecAndPtOfFace(eps,coords->begin(),stFaceConn,endFaceConn,vPtr,pPtr);
8677 stFaceConn=endFaceConn+1;
8679 pPtr=p->getPointer(); vPtr=v->getPointer();
8680 DataArrayInt *comm1=0,*commI1=0;
8681 v->findCommonTuples(eps,-1,comm1,commI1);
8682 MCAuto<DataArrayInt> comm1Auto(comm1),commI1Auto(commI1);
8683 const int *comm1Ptr=comm1->begin();
8684 const int *commI1Ptr=commI1->begin();
8685 int nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
8686 res->pushBackSilent((int)INTERP_KERNEL::NORM_POLYHED);
8688 MCAuto<MEDCouplingUMesh> mm=MEDCouplingUMesh::New("",3);
8689 mm->setCoords(const_cast<DataArrayDouble *>(coords)); mm->allocateCells(1); mm->insertNextCell(INTERP_KERNEL::NORM_POLYHED,(int)std::distance(begin+1,end),begin+1);
8690 mm->finishInsertingCells();
8692 for(int i=0;i<nbOfGrps1;i++)
8694 int vecId=comm1Ptr[commI1Ptr[i]];
8695 MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
8696 DataArrayInt *comm2=0,*commI2=0;
8697 tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
8698 MCAuto<DataArrayInt> comm2Auto(comm2),commI2Auto(commI2);
8699 const int *comm2Ptr=comm2->begin();
8700 const int *commI2Ptr=commI2->begin();
8701 int nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
8702 for(int j=0;j<nbOfGrps2;j++)
8704 if(commI2Ptr[j+1]-commI2Ptr[j]<=1)
8706 res->insertAtTheEnd(begin,end);
8707 res->pushBackSilent(-1);
8711 int pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
8712 MCAuto<DataArrayInt> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
8713 ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
8714 DataArrayInt *tmp0=DataArrayInt::New(),*tmp1=DataArrayInt::New(),*tmp2=DataArrayInt::New(),*tmp3=DataArrayInt::New();
8715 MCAuto<MEDCouplingUMesh> mm2=mm->buildDescendingConnectivity(tmp0,tmp1,tmp2,tmp3); tmp0->decrRef(); tmp1->decrRef(); tmp2->decrRef(); tmp3->decrRef();
8716 MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(mm2->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
8717 MCAuto<DataArrayInt> idsNodeTmp=mm3->zipCoordsTraducer();
8718 MCAuto<DataArrayInt> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
8719 const int *idsNodePtr=idsNode->begin();
8720 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];
8721 double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
8722 double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
8723 if(std::abs(norm)>eps)
8725 double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
8726 mm3->rotate(center,vec,angle);
8728 mm3->changeSpaceDimension(2);
8729 MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
8730 const int *conn4=mm4->getNodalConnectivity()->begin();
8731 const int *connI4=mm4->getNodalConnectivityIndex()->begin();
8732 int nbOfCells=mm4->getNumberOfCells();
8733 for(int k=0;k<nbOfCells;k++)
8736 for(const int *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
8737 res->pushBackSilent(idsNodePtr[*work]);
8738 res->pushBackSilent(-1);
8743 res->popBackSilent();
8747 * 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
8748 * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
8750 * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
8751 * \param [in] coords coordinates expected to have 3 components.
8752 * \param [in] begin start of the nodal connectivity of the face.
8753 * \param [in] end end of the nodal connectivity (excluded) of the face.
8754 * \param [out] v the normalized vector of size 3
8755 * \param [out] p the pos of plane
8757 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const int *begin, const int *end, double *v, double *p)
8759 std::size_t nbPoints=std::distance(begin,end);
8761 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
8762 double vec[3]={0.,0.,0.};
8764 bool refFound=false;
8765 for(;j<nbPoints-1 && !refFound;j++)
8767 vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
8768 vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
8769 vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
8770 double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
8774 vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
8777 for(std::size_t i=j;i<nbPoints-1;i++)
8780 curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
8781 curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
8782 curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
8783 double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
8786 curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
8787 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];
8788 norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
8791 v[0]/=norm; v[1]/=norm; v[2]/=norm;
8792 *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
8796 throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
8800 * This method tries to obtain a well oriented polyhedron.
8801 * If the algorithm fails, an exception will be thrown.
8803 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(int *begin, int *end, const double *coords)
8805 std::list< std::pair<int,int> > edgesOK,edgesFinished;
8806 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
8807 std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
8809 int *bgFace=begin,*endFace=std::find(begin+1,end,-1);
8810 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
8811 for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<int,int> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
8813 while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
8816 std::size_t smthChanged=0;
8817 for(std::size_t i=0;i<nbOfFaces;i++)
8819 endFace=std::find(bgFace+1,end,-1);
8820 nbOfEdgesInFace=std::distance(bgFace,endFace);
8824 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8826 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8827 std::pair<int,int> p2(p1.second,p1.first);
8828 bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
8829 bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
8830 if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
8835 std::reverse(bgFace+1,endFace);
8836 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8838 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8839 std::pair<int,int> p2(p1.second,p1.first);
8840 if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
8841 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
8842 if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
8843 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
8844 std::list< std::pair<int,int> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
8845 if(it!=edgesOK.end())
8848 edgesFinished.push_back(p1);
8851 edgesOK.push_back(p1);
8858 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
8860 if(!edgesOK.empty())
8861 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
8862 if(INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)<-EPS_FOR_POLYH_ORIENTATION)
8863 {//not lucky ! The first face was not correctly oriented : reorient all faces...
8865 for(std::size_t i=0;i<nbOfFaces;i++)
8867 endFace=std::find(bgFace+1,end,-1);
8868 std::reverse(bgFace+1,endFace);
8874 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMeshLinear(const MEDCouplingUMesh *skin, const DataArrayInt *n2o) const
8876 int nbOfNodesExpected(skin->getNumberOfNodes());
8877 const int *n2oPtr(n2o->begin());
8878 MCAuto<DataArrayInt> revNodal(DataArrayInt::New()),revNodalI(DataArrayInt::New());
8879 skin->getReverseNodalConnectivity(revNodal,revNodalI);
8880 const int *revNodalPtr(revNodal->begin()),*revNodalIPtr(revNodalI->begin());
8881 const int *nodalPtr(skin->getNodalConnectivity()->begin());
8882 const int *nodalIPtr(skin->getNodalConnectivityIndex()->begin());
8883 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfNodesExpected+1,1);
8884 int *work(ret->getPointer()); *work++=INTERP_KERNEL::NORM_POLYGON;
8885 if(nbOfNodesExpected<1)
8887 int prevCell(0),prevNode(nodalPtr[nodalIPtr[0]+1]);
8888 *work++=n2oPtr[prevNode];
8889 for(int i=1;i<nbOfNodesExpected;i++)
8891 if(nodalIPtr[prevCell+1]-nodalIPtr[prevCell]==3)
8893 std::set<int> conn(nodalPtr+nodalIPtr[prevCell]+1,nodalPtr+nodalIPtr[prevCell]+3);
8894 conn.erase(prevNode);
8897 int curNode(*(conn.begin()));
8898 *work++=n2oPtr[curNode];
8899 std::set<int> shar(revNodalPtr+revNodalIPtr[curNode],revNodalPtr+revNodalIPtr[curNode+1]);
8900 shar.erase(prevCell);
8903 prevCell=*(shar.begin());
8907 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected 2 !");
8910 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected 1 !");
8913 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected cell !");
8918 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMeshQuadratic(const MEDCouplingUMesh *skin, const DataArrayInt *n2o) const
8920 int nbOfNodesExpected(skin->getNumberOfNodes());
8921 int nbOfTurn(nbOfNodesExpected/2);
8922 const int *n2oPtr(n2o->begin());
8923 MCAuto<DataArrayInt> revNodal(DataArrayInt::New()),revNodalI(DataArrayInt::New());
8924 skin->getReverseNodalConnectivity(revNodal,revNodalI);
8925 const int *revNodalPtr(revNodal->begin()),*revNodalIPtr(revNodalI->begin());
8926 const int *nodalPtr(skin->getNodalConnectivity()->begin());
8927 const int *nodalIPtr(skin->getNodalConnectivityIndex()->begin());
8928 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfNodesExpected+1,1);
8929 int *work(ret->getPointer()); *work++=INTERP_KERNEL::NORM_QPOLYG;
8930 if(nbOfNodesExpected<1)
8932 int prevCell(0),prevNode(nodalPtr[nodalIPtr[0]+1]);
8933 *work=n2oPtr[prevNode]; work[nbOfTurn]=n2oPtr[nodalPtr[nodalIPtr[0]+3]]; work++;
8934 for(int i=1;i<nbOfTurn;i++)
8936 if(nodalIPtr[prevCell+1]-nodalIPtr[prevCell]==4)
8938 std::set<int> conn(nodalPtr+nodalIPtr[prevCell]+1,nodalPtr+nodalIPtr[prevCell]+3);
8939 conn.erase(prevNode);
8942 int curNode(*(conn.begin()));
8943 *work=n2oPtr[curNode];
8944 std::set<int> shar(revNodalPtr+revNodalIPtr[curNode],revNodalPtr+revNodalIPtr[curNode+1]);
8945 shar.erase(prevCell);
8948 int curCell(*(shar.begin()));
8949 work[nbOfTurn]=n2oPtr[nodalPtr[nodalIPtr[curCell]+3]];
8955 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected 2 !");
8958 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected 1 !");
8961 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected cell !");
8967 * This method makes the assumption spacedimension == meshdimension == 2.
8968 * This method works only for linear cells.
8970 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
8972 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMesh() const
8974 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
8975 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
8976 MCAuto<MEDCouplingUMesh> skin(computeSkin());
8977 int oldNbOfNodes(skin->getNumberOfNodes());
8978 MCAuto<DataArrayInt> o2n(skin->zipCoordsTraducer());
8979 int nbOfNodesExpected(skin->getNumberOfNodes());
8980 MCAuto<DataArrayInt> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
8981 int nbCells(skin->getNumberOfCells());
8982 if(nbCells==nbOfNodesExpected)
8983 return buildUnionOf2DMeshLinear(skin,n2o);
8984 else if(2*nbCells==nbOfNodesExpected)
8985 return buildUnionOf2DMeshQuadratic(skin,n2o);
8987 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
8991 * This method makes the assumption spacedimension == meshdimension == 3.
8992 * This method works only for linear cells.
8994 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
8996 DataArrayInt *MEDCouplingUMesh::buildUnionOf3DMesh() const
8998 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8999 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
9000 MCAuto<MEDCouplingUMesh> m=computeSkin();
9001 const int *conn=m->getNodalConnectivity()->begin();
9002 const int *connI=m->getNodalConnectivityIndex()->begin();
9003 int nbOfCells=m->getNumberOfCells();
9004 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
9005 int *work=ret->getPointer(); *work++=INTERP_KERNEL::NORM_POLYHED;
9008 work=std::copy(conn+connI[0]+1,conn+connI[1],work);
9009 for(int i=1;i<nbOfCells;i++)
9012 work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
9018 * \brief Creates a graph of cell neighbors
9019 * \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
9020 * In the sky line array, graph arcs are stored in terms of (index,value) notation.
9022 * - index: 0 3 5 6 6
9023 * - value: 1 2 3 2 3 3
9024 * means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
9025 * Arcs are not doubled but reflexive (1,1) arcs are present for each cell
9027 MEDCouplingSkyLineArray *MEDCouplingUMesh::generateGraph() const
9029 checkConnectivityFullyDefined();
9031 int meshDim = this->getMeshDimension();
9032 MEDCoupling::DataArrayInt* indexr=MEDCoupling::DataArrayInt::New();
9033 MEDCoupling::DataArrayInt* revConn=MEDCoupling::DataArrayInt::New();
9034 this->getReverseNodalConnectivity(revConn,indexr);
9035 const int* indexr_ptr=indexr->begin();
9036 const int* revConn_ptr=revConn->begin();
9038 const MEDCoupling::DataArrayInt* index;
9039 const MEDCoupling::DataArrayInt* conn;
9040 conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
9041 index=this->getNodalConnectivityIndex();
9042 int nbCells=this->getNumberOfCells();
9043 const int* index_ptr=index->begin();
9044 const int* conn_ptr=conn->begin();
9046 //creating graph arcs (cell to cell relations)
9047 //arcs are stored in terms of (index,value) notation
9050 // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
9051 // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
9053 //warning here one node have less than or equal effective number of cell with it
9054 //but cell could have more than effective nodes
9055 //because other equals nodes in other domain (with other global inode)
9056 std::vector <int> cell2cell_index(nbCells+1,0);
9057 std::vector <int> cell2cell;
9058 cell2cell.reserve(3*nbCells);
9060 for (int icell=0; icell<nbCells;icell++)
9062 std::map<int,int > counter;
9063 for (int iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
9065 int inode=conn_ptr[iconn];
9066 for (int iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
9068 int icell2=revConn_ptr[iconnr];
9069 std::map<int,int>::iterator iter=counter.find(icell2);
9070 if (iter!=counter.end()) (iter->second)++;
9071 else counter.insert(std::make_pair(icell2,1));
9074 for (std::map<int,int>::const_iterator iter=counter.begin();
9075 iter!=counter.end(); iter++)
9076 if (iter->second >= meshDim)
9078 cell2cell_index[icell+1]++;
9079 cell2cell.push_back(iter->first);
9084 cell2cell_index[0]=0;
9085 for (int icell=0; icell<nbCells;icell++)
9086 cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
9088 //filling up index and value to create skylinearray structure
9089 MEDCouplingSkyLineArray* array=new MEDCouplingSkyLineArray(cell2cell_index,cell2cell);
9094 * This method put in zip format into parameter 'zipFrmt' in full interlace mode.
9095 * This format is often asked by INTERP_KERNEL algorithms to avoid many indirections into coordinates array.
9097 void MEDCouplingUMesh::FillInCompact3DMode(int spaceDim, int nbOfNodesInCell, const int *conn, const double *coo, double *zipFrmt)
9101 for(int i=0;i<nbOfNodesInCell;i++)
9102 w=std::copy(coo+3*conn[i],coo+3*conn[i]+3,w);
9103 else if(spaceDim==2)
9105 for(int i=0;i<nbOfNodesInCell;i++)
9107 w=std::copy(coo+2*conn[i],coo+2*conn[i]+2,w);
9112 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::FillInCompact3DMode : Invalid spaceDim specified : must be 2 or 3 !");
9115 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
9117 int nbOfCells=getNumberOfCells();
9119 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
9120 ofs << " <" << getVTKDataSetType() << ">\n";
9121 ofs << " <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
9122 ofs << " <PointData>\n" << pointData << std::endl;
9123 ofs << " </PointData>\n";
9124 ofs << " <CellData>\n" << cellData << std::endl;
9125 ofs << " </CellData>\n";
9126 ofs << " <Points>\n";
9127 if(getSpaceDimension()==3)
9128 _coords->writeVTK(ofs,8,"Points",byteData);
9131 MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
9132 coo->writeVTK(ofs,8,"Points",byteData);
9134 ofs << " </Points>\n";
9135 ofs << " <Cells>\n";
9136 const int *cPtr=_nodal_connec->begin();
9137 const int *cIPtr=_nodal_connec_index->begin();
9138 MCAuto<DataArrayInt> faceoffsets=DataArrayInt::New(); faceoffsets->alloc(nbOfCells,1);
9139 MCAuto<DataArrayInt> types=DataArrayInt::New(); types->alloc(nbOfCells,1);
9140 MCAuto<DataArrayInt> offsets=DataArrayInt::New(); offsets->alloc(nbOfCells,1);
9141 MCAuto<DataArrayInt> connectivity=DataArrayInt::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
9142 int *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
9143 int szFaceOffsets=0,szConn=0;
9144 for(int i=0;i<nbOfCells;i++,w1++,w2++,w3++)
9147 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
9150 *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
9151 w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
9155 int deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
9156 *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
9157 std::set<int> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
9158 *w3=szConn+(int)c.size(); szConn+=(int)c.size();
9159 w4=std::copy(c.begin(),c.end(),w4);
9162 types->transformWithIndArr(MEDCOUPLING2VTKTYPETRADUCER,MEDCOUPLING2VTKTYPETRADUCER+INTERP_KERNEL::NORM_MAXTYPE+1);
9163 types->writeVTK(ofs,8,"UInt8","types",byteData);
9164 offsets->writeVTK(ofs,8,"Int32","offsets",byteData);
9165 if(szFaceOffsets!=0)
9166 {//presence of Polyhedra
9167 connectivity->reAlloc(szConn);
9168 faceoffsets->writeVTK(ofs,8,"Int32","faceoffsets",byteData);
9169 MCAuto<DataArrayInt> faces=DataArrayInt::New(); faces->alloc(szFaceOffsets,1);
9170 w1=faces->getPointer();
9171 for(int i=0;i<nbOfCells;i++)
9172 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
9174 int nbFaces=std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1)+1;
9176 const int *w6=cPtr+cIPtr[i]+1,*w5=0;
9177 for(int j=0;j<nbFaces;j++)
9179 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
9180 *w1++=(int)std::distance(w6,w5);
9181 w1=std::copy(w6,w5,w1);
9185 faces->writeVTK(ofs,8,"Int32","faces",byteData);
9187 connectivity->writeVTK(ofs,8,"Int32","connectivity",byteData);
9188 ofs << " </Cells>\n";
9189 ofs << " </Piece>\n";
9190 ofs << " </" << getVTKDataSetType() << ">\n";
9193 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
9195 stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
9197 { stream << " Not set !"; return ; }
9198 stream << " Mesh dimension : " << _mesh_dim << ".";
9202 { stream << " No coordinates set !"; return ; }
9203 if(!_coords->isAllocated())
9204 { stream << " Coordinates set but not allocated !"; return ; }
9205 stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
9206 stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
9207 if(!_nodal_connec_index)
9208 { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
9209 if(!_nodal_connec_index->isAllocated())
9210 { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
9211 int lgth=_nodal_connec_index->getNumberOfTuples();
9212 int cpt=_nodal_connec_index->getNumberOfComponents();
9213 if(cpt!=1 || lgth<1)
9215 stream << std::endl << "Number of cells : " << lgth-1 << ".";
9218 std::string MEDCouplingUMesh::getVTKDataSetType() const
9220 return std::string("UnstructuredGrid");
9223 std::string MEDCouplingUMesh::getVTKFileExtension() const
9225 return std::string("vtu");
9229 * Partitions the first given 2D mesh using the second given 2D mesh as a tool, and
9230 * returns a result mesh constituted by polygons.
9231 * Thus the final result contains all nodes from m1 plus new nodes. However it doesn't necessarily contains
9232 * all nodes from m2.
9233 * The meshes should be in 2D space. In
9234 * addition, returns two arrays mapping cells of the result mesh to cells of the input
9236 * \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
9237 * 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)
9238 * \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
9239 * 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)
9240 * \param [in] eps - precision used to detect coincident mesh entities.
9241 * \param [out] cellNb1 - a new instance of DataArrayInt holding for each result
9242 * cell an id of the cell of \a m1 it comes from. The caller is to delete
9243 * this array using decrRef() as it is no more needed.
9244 * \param [out] cellNb2 - a new instance of DataArrayInt holding for each result
9245 * cell an id of the cell of \a m2 it comes from. -1 value means that a
9246 * result cell comes from a cell (or part of cell) of \a m1 not overlapped by
9247 * any cell of \a m2. The caller is to delete this array using decrRef() as
9248 * it is no more needed.
9249 * \return MEDCouplingUMesh * - the result 2D mesh which is a new instance of
9250 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
9251 * is no more needed.
9252 * \throw If the coordinates array is not set in any of the meshes.
9253 * \throw If the nodal connectivity of cells is not defined in any of the meshes.
9254 * \throw If any of the meshes is not a 2D mesh in 2D space.
9256 * \sa conformize2D, mergeNodes
9258 MEDCouplingUMesh *MEDCouplingUMesh::Intersect2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2,
9259 double eps, DataArrayInt *&cellNb1, DataArrayInt *&cellNb2)
9262 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshes : input meshes must be not NULL !");
9263 m1->checkFullyDefined();
9264 m2->checkFullyDefined();
9265 if(m1->getMeshDimension()!=2 || m1->getSpaceDimension()!=2 || m2->getMeshDimension()!=2 || m2->getSpaceDimension()!=2)
9266 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshes works on umeshes m1 AND m2 with meshdim equal to 2 and spaceDim equal to 2 too!");
9268 // Step 1: compute all edge intersections (new nodes)
9269 std::vector< std::vector<int> > intersectEdge1, colinear2, subDiv2;
9270 MEDCouplingUMesh *m1Desc=0,*m2Desc=0; // descending connec. meshes
9271 DataArrayInt *desc1=0,*descIndx1=0,*revDesc1=0,*revDescIndx1=0,*desc2=0,*descIndx2=0,*revDesc2=0,*revDescIndx2=0;
9272 std::vector<double> addCoo,addCoordsQuadratic; // coordinates of newly created nodes
9273 IntersectDescending2DMeshes(m1,m2,eps,intersectEdge1,colinear2, subDiv2,
9274 m1Desc,desc1,descIndx1,revDesc1,revDescIndx1,
9275 addCoo, m2Desc,desc2,descIndx2,revDesc2,revDescIndx2);
9276 revDesc1->decrRef(); revDescIndx1->decrRef(); revDesc2->decrRef(); revDescIndx2->decrRef();
9277 MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(desc2),dd4(descIndx2);
9278 MCAuto<MEDCouplingUMesh> dd5(m1Desc),dd6(m2Desc);
9280 // Step 2: re-order newly created nodes according to the ordering found in m2
9281 std::vector< std::vector<int> > intersectEdge2;
9282 BuildIntersectEdges(m1Desc,m2Desc,addCoo,subDiv2,intersectEdge2);
9283 subDiv2.clear(); dd5=0; dd6=0;
9286 std::vector<int> cr,crI; //no DataArrayInt because interface with Geometric2D
9287 std::vector<int> cNb1,cNb2; //no DataArrayInt because interface with Geometric2D
9288 BuildIntersecting2DCellsFromEdges(eps,m1,desc1->begin(),descIndx1->begin(),intersectEdge1,colinear2,m2,desc2->begin(),descIndx2->begin(),intersectEdge2,addCoo,
9289 /* outputs -> */addCoordsQuadratic,cr,crI,cNb1,cNb2);
9291 // Step 4: Prepare final result:
9292 MCAuto<DataArrayDouble> addCooDa(DataArrayDouble::New());
9293 addCooDa->alloc((int)(addCoo.size())/2,2);
9294 std::copy(addCoo.begin(),addCoo.end(),addCooDa->getPointer());
9295 MCAuto<DataArrayDouble> addCoordsQuadraticDa(DataArrayDouble::New());
9296 addCoordsQuadraticDa->alloc((int)(addCoordsQuadratic.size())/2,2);
9297 std::copy(addCoordsQuadratic.begin(),addCoordsQuadratic.end(),addCoordsQuadraticDa->getPointer());
9298 std::vector<const DataArrayDouble *> coordss(4);
9299 coordss[0]=m1->getCoords(); coordss[1]=m2->getCoords(); coordss[2]=addCooDa; coordss[3]=addCoordsQuadraticDa;
9300 MCAuto<DataArrayDouble> coo(DataArrayDouble::Aggregate(coordss));
9301 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("Intersect2D",2));
9302 MCAuto<DataArrayInt> conn(DataArrayInt::New()); conn->alloc((int)cr.size(),1); std::copy(cr.begin(),cr.end(),conn->getPointer());
9303 MCAuto<DataArrayInt> connI(DataArrayInt::New()); connI->alloc((int)crI.size(),1); std::copy(crI.begin(),crI.end(),connI->getPointer());
9304 MCAuto<DataArrayInt> c1(DataArrayInt::New()); c1->alloc((int)cNb1.size(),1); std::copy(cNb1.begin(),cNb1.end(),c1->getPointer());
9305 MCAuto<DataArrayInt> c2(DataArrayInt::New()); c2->alloc((int)cNb2.size(),1); std::copy(cNb2.begin(),cNb2.end(),c2->getPointer());
9306 ret->setConnectivity(conn,connI,true);
9307 ret->setCoords(coo);
9308 cellNb1=c1.retn(); cellNb2=c2.retn();
9314 bool IsColinearOfACellOf(const std::vector< std::vector<int> >& intersectEdge1, const std::vector<int>& candidates, int start, int stop, int& retVal)
9316 if(candidates.empty())
9318 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
9320 const std::vector<int>& pool(intersectEdge1[*it]);
9321 int tmp[2]; tmp[0]=start; tmp[1]=stop;
9322 if(std::search(pool.begin(),pool.end(),tmp,tmp+2)!=pool.end())
9327 tmp[0]=stop; tmp[1]=start;
9328 if(std::search(pool.begin(),pool.end(),tmp,tmp+2)!=pool.end())
9337 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,
9338 MCAuto<DataArrayInt>& idsInRetColinear, MCAuto<DataArrayInt>& idsInMesh1DForIdsInRetColinear)
9340 idsInRetColinear=DataArrayInt::New(); idsInRetColinear->alloc(0,1);
9341 idsInMesh1DForIdsInRetColinear=DataArrayInt::New(); idsInMesh1DForIdsInRetColinear->alloc(0,1);
9342 int nCells(mesh1D->getNumberOfCells());
9343 if(nCells!=(int)intersectEdge2.size())
9344 throw INTERP_KERNEL::Exception("BuildMesh1DCutFrom : internal error # 1 !");
9345 const DataArrayDouble *coo2(mesh1D->getCoords());
9346 const int *c(mesh1D->getNodalConnectivity()->begin()),*ci(mesh1D->getNodalConnectivityIndex()->begin());
9347 const double *coo2Ptr(coo2->begin());
9348 int offset1(coords1->getNumberOfTuples());
9349 int offset2(offset1+coo2->getNumberOfTuples());
9350 int offset3(offset2+addCoo.size()/2);
9351 std::vector<double> addCooQuad;
9352 MCAuto<DataArrayInt> cOut(DataArrayInt::New()),ciOut(DataArrayInt::New()); cOut->alloc(0,1); ciOut->alloc(1,1); ciOut->setIJ(0,0,0);
9353 int tmp[4],cicnt(0),kk(0);
9354 for(int i=0;i<nCells;i++)
9356 std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
9357 INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coo2Ptr,m));
9358 const std::vector<int>& subEdges(intersectEdge2[i]);
9359 int nbSubEdge(subEdges.size()/2);
9360 for(int j=0;j<nbSubEdge;j++,kk++)
9362 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));
9363 MCAuto<INTERP_KERNEL::Edge> e2(e->buildEdgeLyingOnMe(n1,n2));
9364 INTERP_KERNEL::Edge *e2Ptr(e2);
9365 std::map<int,int>::const_iterator itm;
9366 if(dynamic_cast<INTERP_KERNEL::EdgeArcCircle *>(e2Ptr))
9368 tmp[0]=INTERP_KERNEL::NORM_SEG3;
9369 itm=mergedNodes.find(subEdges[2*j]);
9370 tmp[1]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j];
9371 itm=mergedNodes.find(subEdges[2*j+1]);
9372 tmp[2]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j+1];
9373 tmp[3]=offset3+(int)addCooQuad.size()/2;
9375 e2->getBarycenter(tmp2); addCooQuad.insert(addCooQuad.end(),tmp2,tmp2+2);
9377 cOut->insertAtTheEnd(tmp,tmp+4);
9378 ciOut->pushBackSilent(cicnt);
9382 tmp[0]=INTERP_KERNEL::NORM_SEG2;
9383 itm=mergedNodes.find(subEdges[2*j]);
9384 tmp[1]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j];
9385 itm=mergedNodes.find(subEdges[2*j+1]);
9386 tmp[2]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j+1];
9388 cOut->insertAtTheEnd(tmp,tmp+3);
9389 ciOut->pushBackSilent(cicnt);
9392 if(IsColinearOfACellOf(intersectEdge1,colinear2[i],tmp[1],tmp[2],tmp00))
9394 idsInRetColinear->pushBackSilent(kk);
9395 idsInMesh1DForIdsInRetColinear->pushBackSilent(tmp00);
9400 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(mesh1D->getName(),1));
9401 ret->setConnectivity(cOut,ciOut,true);
9402 MCAuto<DataArrayDouble> arr3(DataArrayDouble::New());
9403 arr3->useArray(&addCoo[0],false,C_DEALLOC,(int)addCoo.size()/2,2);
9404 MCAuto<DataArrayDouble> arr4(DataArrayDouble::New()); arr4->useArray(&addCooQuad[0],false,C_DEALLOC,(int)addCooQuad.size()/2,2);
9405 std::vector<const DataArrayDouble *> coordss(4);
9406 coordss[0]=coords1; coordss[1]=mesh1D->getCoords(); coordss[2]=arr3; coordss[3]=arr4;
9407 MCAuto<DataArrayDouble> arr(DataArrayDouble::Aggregate(coordss));
9408 ret->setCoords(arr);
9412 MEDCouplingUMesh *BuildRefined2DCellLinear(const DataArrayDouble *coords, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9414 std::vector<int> allEdges;
9415 for(const int *it2(descBg);it2!=descEnd;it2++)
9417 const std::vector<int>& edge1(intersectEdge1[std::abs(*it2)-1]);
9419 allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9421 allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9423 std::size_t nb(allEdges.size());
9425 throw INTERP_KERNEL::Exception("BuildRefined2DCellLinear : internal error 1 !");
9426 std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9427 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
9428 ret->setCoords(coords);
9429 ret->allocateCells(1);
9430 std::vector<int> connOut(nbOfEdgesOf2DCellSplit);
9431 for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9432 connOut[kk]=allEdges[2*kk];
9433 ret->insertNextCell(INTERP_KERNEL::NORM_POLYGON,connOut.size(),&connOut[0]);
9437 MEDCouplingUMesh *BuildRefined2DCellQuadratic(const DataArrayDouble *coords, const MEDCouplingUMesh *mesh2D, int cellIdInMesh2D, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9439 const int *c(mesh2D->getNodalConnectivity()->begin()),*ci(mesh2D->getNodalConnectivityIndex()->begin());
9440 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[cellIdInMesh2D]]));
9442 unsigned sz(cm.getNumberOfSons2(c+ci[cellIdInMesh2D]+1,ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]-1));
9443 if(sz!=std::distance(descBg,descEnd))
9444 throw INTERP_KERNEL::Exception("BuildRefined2DCellQuadratic : internal error 1 !");
9445 INTERP_KERNEL::AutoPtr<int> tmpPtr(new int[ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]]);
9446 std::vector<int> allEdges,centers;
9447 const double *coordsPtr(coords->begin());
9448 MCAuto<DataArrayDouble> addCoo(DataArrayDouble::New()); addCoo->alloc(0,1);
9449 int offset(coords->getNumberOfTuples());
9450 for(const int *it2(descBg);it2!=descEnd;it2++,ii++)
9452 INTERP_KERNEL::NormalizedCellType typeOfSon;
9453 cm.fillSonCellNodalConnectivity2(ii,c+ci[cellIdInMesh2D]+1,ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]-1,tmpPtr,typeOfSon);
9454 const std::vector<int>& edge1(intersectEdge1[std::abs(*it2)-1]);
9456 allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9458 allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9460 centers.push_back(tmpPtr[2]);//special case where no subsplit of edge -> reuse the original center.
9462 {//the current edge has been subsplit -> create corresponding centers.
9463 std::size_t nbOfCentersToAppend(edge1.size()/2);
9464 std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9465 MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpPtr,coordsPtr,m));
9466 std::vector<int>::const_iterator it3(allEdges.end()-edge1.size());
9467 for(std::size_t k=0;k<nbOfCentersToAppend;k++)
9470 const double *aa(coordsPtr+2*(*it3++));
9471 const double *bb(coordsPtr+2*(*it3++));
9472 ee->getMiddleOfPoints(aa,bb,tmpp);
9473 addCoo->insertAtTheEnd(tmpp,tmpp+2);
9474 centers.push_back(offset+k);
9478 std::size_t nb(allEdges.size());
9480 throw INTERP_KERNEL::Exception("BuildRefined2DCellQuadratic : internal error 2 !");
9481 std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9482 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
9484 ret->setCoords(coords);
9487 addCoo->rearrange(2);
9488 addCoo=DataArrayDouble::Aggregate(coords,addCoo);
9489 ret->setCoords(addCoo);
9491 ret->allocateCells(1);
9492 std::vector<int> connOut(nbOfEdgesOf2DCellSplit);
9493 for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9494 connOut[kk]=allEdges[2*kk];
9495 connOut.insert(connOut.end(),centers.begin(),centers.end());
9496 ret->insertNextCell(INTERP_KERNEL::NORM_QPOLYG,connOut.size(),&connOut[0]);
9501 * This method creates a refinement of a cell in \a mesh2D. Those cell is defined by descending connectivity and the sorted subdivided nodal connectivity
9504 * \param [in] mesh2D - The origin 2D mesh. \b Warning \b coords are not those of \a mesh2D. But mesh2D->getCoords()==coords[:mesh2D->getNumberOfNodes()]
9506 MEDCouplingUMesh *BuildRefined2DCell(const DataArrayDouble *coords, const MEDCouplingUMesh *mesh2D, int cellIdInMesh2D, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9508 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(mesh2D->getTypeOfCell(cellIdInMesh2D)));
9509 if(!cm.isQuadratic())
9510 return BuildRefined2DCellLinear(coords,descBg,descEnd,intersectEdge1);
9512 return BuildRefined2DCellQuadratic(coords,mesh2D,cellIdInMesh2D,descBg,descEnd,intersectEdge1);
9515 void AddCellInMesh2D(MEDCouplingUMesh *mesh2D, const std::vector<int>& conn, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edges)
9518 for(std::vector< MCAuto<INTERP_KERNEL::Edge> >::const_iterator it=edges.begin();it!=edges.end();it++)
9520 const INTERP_KERNEL::Edge *ee(*it);
9521 if(dynamic_cast<const INTERP_KERNEL::EdgeArcCircle *>(ee))
9525 mesh2D->insertNextCell(INTERP_KERNEL::NORM_POLYGON,conn.size(),&conn[0]);
9528 const double *coo(mesh2D->getCoords()->begin());
9529 std::size_t sz(conn.size());
9530 std::vector<double> addCoo;
9531 std::vector<int> conn2(conn);
9532 int offset(mesh2D->getNumberOfNodes());
9533 for(std::size_t i=0;i<sz;i++)
9536 edges[(i+1)%sz]->getMiddleOfPoints(coo+2*conn[i],coo+2*conn[(i+1)%sz],tmp);// tony a chier i+1 -> i
9537 addCoo.insert(addCoo.end(),tmp,tmp+2);
9538 conn2.push_back(offset+(int)i);
9540 mesh2D->getCoords()->rearrange(1);
9541 mesh2D->getCoords()->pushBackValsSilent(&addCoo[0],&addCoo[0]+addCoo.size());
9542 mesh2D->getCoords()->rearrange(2);
9543 mesh2D->insertNextCell(INTERP_KERNEL::NORM_QPOLYG,conn2.size(),&conn2[0]);
9548 * \b WARNING edges in out1 coming from \a splitMesh1D are \b NOT oriented because only used for equation of curve.
9550 * This method cuts in 2 parts the input 2D cell given using boundaries description (\a edge1Bis and \a edge1BisPtr) using
9551 * a set of edges defined in \a splitMesh1D.
9553 void BuildMesh2DCutInternal2(const MEDCouplingUMesh *splitMesh1D, const std::vector<int>& edge1Bis, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edge1BisPtr,
9554 std::vector< std::vector<int> >& out0, std::vector< std::vector< MCAuto<INTERP_KERNEL::Edge> > >& out1)
9556 std::size_t nb(edge1Bis.size()/2);
9557 std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9558 int iEnd(splitMesh1D->getNumberOfCells());
9560 throw INTERP_KERNEL::Exception("BuildMesh2DCutInternal2 : internal error ! input 1D mesh must have at least one cell !");
9562 const int *cSplitPtr(splitMesh1D->getNodalConnectivity()->begin()),*ciSplitPtr(splitMesh1D->getNodalConnectivityIndex()->begin());
9563 for(ii=0;ii<nb && edge1Bis[2*ii]!=cSplitPtr[ciSplitPtr[0]+1];ii++);
9564 for(jj=ii;jj<nb && edge1Bis[2*jj+1]!=cSplitPtr[ciSplitPtr[iEnd-1]+2];jj++);
9567 {//the edges splitMesh1D[iStart:iEnd] does not fully cut the current 2D cell -> single output cell
9568 out0.resize(1); out1.resize(1);
9569 std::vector<int>& connOut(out0[0]);
9570 connOut.resize(nbOfEdgesOf2DCellSplit);
9571 std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr(out1[0]);
9572 edgesPtr.resize(nbOfEdgesOf2DCellSplit);
9573 for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9575 connOut[kk]=edge1Bis[2*kk];
9576 edgesPtr[kk]=edge1BisPtr[2*kk];
9581 // [i,iEnd[ contains the
9582 out0.resize(2); out1.resize(2);
9583 std::vector<int>& connOutLeft(out0[0]);
9584 std::vector<int>& connOutRight(out0[1]);//connOutLeft should end with edge1Bis[2*ii] and connOutRight should end with edge1Bis[2*jj+1]
9585 std::vector< MCAuto<INTERP_KERNEL::Edge> >& eleft(out1[0]);
9586 std::vector< MCAuto<INTERP_KERNEL::Edge> >& eright(out1[1]);
9587 for(std::size_t k=ii;k<jj+1;k++)
9588 { connOutLeft.push_back(edge1Bis[2*k+1]); eleft.push_back(edge1BisPtr[2*k+1]); }
9589 std::vector< MCAuto<INTERP_KERNEL::Edge> > ees(iEnd);
9590 for(int ik=0;ik<iEnd;ik++)
9592 std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9593 MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)cSplitPtr[ciSplitPtr[ik]],cSplitPtr+ciSplitPtr[ik]+1,splitMesh1D->getCoords()->begin(),m));
9596 for(int ik=iEnd-1;ik>=0;ik--)
9597 connOutLeft.push_back(cSplitPtr[ciSplitPtr[ik]+1]);
9598 for(std::size_t k=jj+1;k<nbOfEdgesOf2DCellSplit+ii;k++)
9599 { connOutRight.push_back(edge1Bis[2*k+1]); eright.push_back(edge1BisPtr[2*k+1]); }
9600 eleft.insert(eleft.end(),ees.rbegin(),ees.rend());
9601 for(int ik=0;ik<iEnd;ik++)
9602 connOutRight.push_back(cSplitPtr[ciSplitPtr[ik]+2]);
9603 eright.insert(eright.end(),ees.begin(),ees.end());
9615 CellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr);
9617 std::vector<int> _edges;
9618 std::vector< MCAuto<INTERP_KERNEL::Edge> > _edges_ptr;
9621 CellInfo::CellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr)
9623 std::size_t nbe(edges.size());
9624 std::vector<int> edges2(2*nbe); std::vector< MCAuto<INTERP_KERNEL::Edge> > edgesPtr2(2*nbe);
9625 for(std::size_t i=0;i<nbe;i++)
9627 edges2[2*i]=edges[i]; edges2[2*i+1]=edges[(i+1)%nbe];
9628 edgesPtr2[2*i]=edgesPtr[(i+1)%nbe]; edgesPtr2[2*i+1]=edgesPtr[(i+1)%nbe];//tony a chier
9630 _edges.resize(4*nbe); _edges_ptr.resize(4*nbe);
9631 std::copy(edges2.begin(),edges2.end(),_edges.begin()); std::copy(edges2.begin(),edges2.end(),_edges.begin()+2*nbe);
9632 std::copy(edgesPtr2.begin(),edgesPtr2.end(),_edges_ptr.begin()); std::copy(edgesPtr2.begin(),edgesPtr2.end(),_edges_ptr.begin()+2*nbe);
9638 EdgeInfo(int istart, int iend, const MCAuto<MEDCouplingUMesh>& mesh):_istart(istart),_iend(iend),_mesh(mesh),_left(-7),_right(-7) { }
9639 EdgeInfo(int istart, int iend, int pos, const MCAuto<INTERP_KERNEL::Edge>& edge):_istart(istart),_iend(iend),_edge(edge),_left(pos),_right(pos+1) { }
9640 bool isInMyRange(int pos) const { return pos>=_istart && pos<_iend; }
9641 void somethingHappendAt(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight);
9642 void feedEdgeInfoAt(double eps, const MEDCouplingUMesh *mesh2D, int offset, int neighbors[2]) const;
9646 MCAuto<MEDCouplingUMesh> _mesh;
9647 MCAuto<INTERP_KERNEL::Edge> _edge;
9652 void EdgeInfo::somethingHappendAt(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight)
9654 const MEDCouplingUMesh *mesh(_mesh);
9660 { _left++; _right++; return ; }
9663 bool isLeft(std::find(newLeft.begin(),newLeft.end(),_edge)!=newLeft.end()),isRight(std::find(newRight.begin(),newRight.end(),_edge)!=newRight.end());
9664 if((isLeft && isRight) || (!isLeft && !isRight))
9665 throw INTERP_KERNEL::Exception("EdgeInfo::somethingHappendAt : internal error # 1 !");
9676 bool isLeft(std::find(newLeft.begin(),newLeft.end(),_edge)!=newLeft.end()),isRight(std::find(newRight.begin(),newRight.end(),_edge)!=newRight.end());
9677 if((isLeft && isRight) || (!isLeft && !isRight))
9678 throw INTERP_KERNEL::Exception("EdgeInfo::somethingHappendAt : internal error # 2 !");
9693 void EdgeInfo::feedEdgeInfoAt(double eps, const MEDCouplingUMesh *mesh2D, int offset, int neighbors[2]) const
9695 const MEDCouplingUMesh *mesh(_mesh);
9698 neighbors[0]=offset+_left; neighbors[1]=offset+_right;
9701 {// not fully splitting cell case
9702 if(mesh2D->getNumberOfCells()==1)
9703 {//little optimization. 1 cell no need to find in which cell mesh is !
9704 neighbors[0]=offset; neighbors[1]=offset;
9709 MCAuto<DataArrayDouble> barys(mesh->computeCellCenterOfMass());
9710 int cellId(mesh2D->getCellContainingPoint(barys->begin(),eps));
9712 throw INTERP_KERNEL::Exception("EdgeInfo::feedEdgeInfoAt : internal error !");
9713 neighbors[0]=offset+cellId; neighbors[1]=offset+cellId;
9718 class VectorOfCellInfo
9721 VectorOfCellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr);
9722 std::size_t size() const { return _pool.size(); }
9723 int getPositionOf(double eps, const MEDCouplingUMesh *mesh) const;
9724 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);
9725 const std::vector<int>& getConnOf(int pos) const { return get(pos)._edges; }
9726 const std::vector< MCAuto<INTERP_KERNEL::Edge> >& getEdgePtrOf(int pos) const { return get(pos)._edges_ptr; }
9727 MCAuto<MEDCouplingUMesh> getZeMesh() const { return _ze_mesh; }
9728 void feedEdgeInfoAt(double eps, int pos, int offset, int neighbors[2]) const;
9730 int getZePosOfEdgeGivenItsGlobalId(int pos) const;
9731 void updateEdgeInfo(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight);
9732 const CellInfo& get(int pos) const;
9733 CellInfo& get(int pos);
9735 std::vector<CellInfo> _pool;
9736 MCAuto<MEDCouplingUMesh> _ze_mesh;
9737 std::vector<EdgeInfo> _edge_info;
9740 VectorOfCellInfo::VectorOfCellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr):_pool(1)
9742 _pool[0]._edges=edges;
9743 _pool[0]._edges_ptr=edgesPtr;
9746 int VectorOfCellInfo::getPositionOf(double eps, const MEDCouplingUMesh *mesh) const
9749 throw INTERP_KERNEL::Exception("VectorOfCellSplitter::getPositionOf : empty !");
9752 const MEDCouplingUMesh *zeMesh(_ze_mesh);
9754 throw INTERP_KERNEL::Exception("VectorOfCellSplitter::getPositionOf : null aggregated mesh !");
9755 MCAuto<DataArrayDouble> barys(mesh->computeCellCenterOfMass());
9756 return zeMesh->getCellContainingPoint(barys->begin(),eps);
9759 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)
9761 get(pos);//to check pos
9762 bool isFast(pos==0 && _pool.size()==1);
9763 std::size_t sz(edges.size());
9764 // dealing with edges
9766 _edge_info.push_back(EdgeInfo(istart,iend,mesh1DInCase));
9768 _edge_info.push_back(EdgeInfo(istart,iend,pos,edgePtrs[0].back()));
9770 std::vector<CellInfo> pool(_pool.size()-1+sz);
9771 for(int i=0;i<pos;i++)
9773 for(std::size_t j=0;j<sz;j++)
9774 pool[pos+j]=CellInfo(edges[j],edgePtrs[j]);
9775 for(int i=pos+1;i<(int)_pool.size();i++)
9776 pool[i+sz-1]=_pool[i];
9780 updateEdgeInfo(pos,edgePtrs[0],edgePtrs[1]);
9788 std::vector< MCAuto<MEDCouplingUMesh> > ms;
9791 MCAuto<MEDCouplingUMesh> elt(static_cast<MEDCouplingUMesh *>(_ze_mesh->buildPartOfMySelfSlice(0,pos,true)));
9795 if(pos<_ze_mesh->getNumberOfCells()-1)
9797 MCAuto<MEDCouplingUMesh> elt(static_cast<MEDCouplingUMesh *>(_ze_mesh->buildPartOfMySelfSlice(pos+1,_ze_mesh->getNumberOfCells(),true)));
9800 std::vector< const MEDCouplingUMesh *> ms2(ms.size());
9801 for(std::size_t j=0;j<ms2.size();j++)
9803 _ze_mesh=MEDCouplingUMesh::MergeUMeshesOnSameCoords(ms2);
9806 void VectorOfCellInfo::feedEdgeInfoAt(double eps, int pos, int offset, int neighbors[2]) const
9808 _edge_info[getZePosOfEdgeGivenItsGlobalId(pos)].feedEdgeInfoAt(eps,_ze_mesh,offset,neighbors);
9811 int VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId(int pos) const
9814 throw INTERP_KERNEL::Exception("VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId : invalid id ! Must be >=0 !");
9816 for(std::vector<EdgeInfo>::const_iterator it=_edge_info.begin();it!=_edge_info.end();it++,ret++)
9818 if((*it).isInMyRange(pos))
9821 throw INTERP_KERNEL::Exception("VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId : invalid id !");
9824 void VectorOfCellInfo::updateEdgeInfo(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight)
9826 get(pos);//to check;
9827 if(_edge_info.empty())
9829 std::size_t sz(_edge_info.size()-1);
9830 for(std::size_t i=0;i<sz;i++)
9831 _edge_info[i].somethingHappendAt(pos,newLeft,newRight);
9834 const CellInfo& VectorOfCellInfo::get(int pos) const
9836 if(pos<0 || pos>=(int)_pool.size())
9837 throw INTERP_KERNEL::Exception("VectorOfCellSplitter::get const : invalid pos !");
9841 CellInfo& VectorOfCellInfo::get(int pos)
9843 if(pos<0 || pos>=(int)_pool.size())
9844 throw INTERP_KERNEL::Exception("VectorOfCellSplitter::get : invalid pos !");
9850 * - a \b closed set of edges ( \a allEdges and \a allEdgesPtr ) that defines the split descending 2D cell.
9851 * - \a splitMesh1D a split 2D curve mesh contained into 2D cell defined above.
9853 * This method returns the 2D mesh and feeds \a idsLeftRight using offset.
9855 * Algorithm : \a splitMesh1D is cut into contiguous parts. Each contiguous parts will build incrementally the output 2D cells.
9857 * \param [in] allEdges a list of pairs (beginNode, endNode). Linked with \a allEdgesPtr to get the equation of edge.
9859 MEDCouplingUMesh *BuildMesh2DCutInternal(double eps, const MEDCouplingUMesh *splitMesh1D, const std::vector<int>& allEdges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& allEdgesPtr, int offset,
9860 MCAuto<DataArrayInt>& idsLeftRight)
9862 int nbCellsInSplitMesh1D(splitMesh1D->getNumberOfCells());
9863 if(nbCellsInSplitMesh1D==0)
9864 throw INTERP_KERNEL::Exception("BuildMesh2DCutInternal : internal error ! input 1D mesh must have at least one cell !");
9865 const int *cSplitPtr(splitMesh1D->getNodalConnectivity()->begin()),*ciSplitPtr(splitMesh1D->getNodalConnectivityIndex()->begin());
9866 std::size_t nb(allEdges.size()),jj;
9868 throw INTERP_KERNEL::Exception("BuildMesh2DCutFrom : internal error 2 !");
9869 std::vector<int> edge1Bis(nb*2);
9870 std::vector< MCAuto<INTERP_KERNEL::Edge> > edge1BisPtr(nb*2);
9871 std::copy(allEdges.begin(),allEdges.end(),edge1Bis.begin());
9872 std::copy(allEdges.begin(),allEdges.end(),edge1Bis.begin()+nb);
9873 std::copy(allEdgesPtr.begin(),allEdgesPtr.end(),edge1BisPtr.begin());
9874 std::copy(allEdgesPtr.begin(),allEdgesPtr.end(),edge1BisPtr.begin()+nb);
9876 idsLeftRight=DataArrayInt::New(); idsLeftRight->alloc(nbCellsInSplitMesh1D*2); idsLeftRight->fillWithValue(-2); idsLeftRight->rearrange(2);
9877 int *idsLeftRightPtr(idsLeftRight->getPointer());
9878 VectorOfCellInfo pool(edge1Bis,edge1BisPtr);
9879 for(int iStart=0;iStart<nbCellsInSplitMesh1D;)
9880 {// split [0:nbCellsInSplitMesh1D) in contiguous parts [iStart:iEnd)
9882 for(;iEnd<nbCellsInSplitMesh1D;)
9884 for(jj=0;jj<nb && edge1Bis[2*jj+1]!=cSplitPtr[ciSplitPtr[iEnd]+2];jj++);
9890 if(iEnd<nbCellsInSplitMesh1D)
9893 MCAuto<MEDCouplingUMesh> partOfSplitMesh1D(static_cast<MEDCouplingUMesh *>(splitMesh1D->buildPartOfMySelfSlice(iStart,iEnd,1,true)));
9894 int pos(pool.getPositionOf(eps,partOfSplitMesh1D));
9896 MCAuto<MEDCouplingUMesh>retTmp(MEDCouplingUMesh::New("",2));
9897 retTmp->setCoords(splitMesh1D->getCoords());
9898 retTmp->allocateCells();
9900 std::vector< std::vector<int> > out0;
9901 std::vector< std::vector< MCAuto<INTERP_KERNEL::Edge> > > out1;
9903 BuildMesh2DCutInternal2(partOfSplitMesh1D,pool.getConnOf(pos),pool.getEdgePtrOf(pos),out0,out1);
9904 for(std::size_t cnt=0;cnt<out0.size();cnt++)
9905 AddCellInMesh2D(retTmp,out0[cnt],out1[cnt]);
9906 pool.setMeshAt(pos,retTmp,iStart,iEnd,partOfSplitMesh1D,out0,out1);
9910 for(int mm=0;mm<nbCellsInSplitMesh1D;mm++)
9911 pool.feedEdgeInfoAt(eps,mm,offset,idsLeftRightPtr+2*mm);
9912 return pool.getZeMesh().retn();
9915 MEDCouplingUMesh *BuildMesh2DCutFrom(double eps, int cellIdInMesh2D, const MEDCouplingUMesh *mesh2DDesc, const MEDCouplingUMesh *splitMesh1D,
9916 const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1, int offset,
9917 MCAuto<DataArrayInt>& idsLeftRight)
9919 const int *cdescPtr(mesh2DDesc->getNodalConnectivity()->begin()),*cidescPtr(mesh2DDesc->getNodalConnectivityIndex()->begin());
9921 std::vector<int> allEdges;
9922 std::vector< MCAuto<INTERP_KERNEL::Edge> > allEdgesPtr; // for each sub edge in splitMesh2D the uncut Edge object of the original mesh2D
9923 for(const int *it(descBg);it!=descEnd;it++) // for all edges in the descending connectivity of the 2D mesh in relative Fortran mode
9925 int edgeId(std::abs(*it)-1);
9926 std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9927 MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)cdescPtr[cidescPtr[edgeId]],cdescPtr+cidescPtr[edgeId]+1,mesh2DDesc->getCoords()->begin(),m));
9928 const std::vector<int>& edge1(intersectEdge1[edgeId]);
9930 allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9932 allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9933 std::size_t sz(edge1.size());
9934 for(std::size_t cnt=0;cnt<sz;cnt++)
9935 allEdgesPtr.push_back(ee);
9938 return BuildMesh2DCutInternal(eps,splitMesh1D,allEdges,allEdgesPtr,offset,idsLeftRight);
9941 bool AreEdgeEqual(const double *coo2D, const INTERP_KERNEL::CellModel& typ1, const int *conn1, const INTERP_KERNEL::CellModel& typ2, const int *conn2, double eps)
9943 if(!typ1.isQuadratic() && !typ2.isQuadratic())
9944 {//easy case comparison not
9945 return conn1[0]==conn2[0] && conn1[1]==conn2[1];
9947 else if(typ1.isQuadratic() && typ2.isQuadratic())
9949 bool status0(conn1[0]==conn2[0] && conn1[1]==conn2[1]);
9952 if(conn1[2]==conn2[2])
9954 const double *a(coo2D+2*conn1[2]),*b(coo2D+2*conn2[2]);
9955 double dist(sqrt((a[0]-b[0])*(a[0]-b[0])+(a[1]-b[1])*(a[1]-b[1])));
9959 {//only one is quadratic
9960 bool status0(conn1[0]==conn2[0] && conn1[1]==conn2[1]);
9963 const double *a(0),*bb(0),*be(0);
9964 if(typ1.isQuadratic())
9966 a=coo2D+2*conn1[2]; bb=coo2D+2*conn2[0]; be=coo2D+2*conn2[1];
9970 a=coo2D+2*conn2[2]; bb=coo2D+2*conn1[0]; be=coo2D+2*conn1[1];
9972 double b[2]; b[0]=(be[0]+bb[0])/2.; b[1]=(be[1]+bb[1])/2.;
9973 double dist(sqrt((a[0]-b[0])*(a[0]-b[0])+(a[1]-b[1])*(a[1]-b[1])));
9979 * This method returns among the cellIds [ \a candidatesIn2DBg , \a candidatesIn2DEnd ) in \a mesh2DSplit those exactly sharing \a cellIdInMesh1DSplitRelative in \a mesh1DSplit.
9980 * \a mesh2DSplit and \a mesh1DSplit are expected to share the coordinates array.
9982 * \param [in] cellIdInMesh1DSplitRelative is in Fortran mode using sign to specify direction.
9984 int FindRightCandidateAmong(const MEDCouplingUMesh *mesh2DSplit, const int *candidatesIn2DBg, const int *candidatesIn2DEnd, const MEDCouplingUMesh *mesh1DSplit, int cellIdInMesh1DSplitRelative, double eps)
9986 if(candidatesIn2DEnd==candidatesIn2DBg)
9987 throw INTERP_KERNEL::Exception("FindRightCandidateAmong : internal error 1 !");
9988 const double *coo(mesh2DSplit->getCoords()->begin());
9989 if(std::distance(candidatesIn2DBg,candidatesIn2DEnd)==1)
9990 return *candidatesIn2DBg;
9991 int edgeId(std::abs(cellIdInMesh1DSplitRelative)-1);
9992 MCAuto<MEDCouplingUMesh> cur1D(static_cast<MEDCouplingUMesh *>(mesh1DSplit->buildPartOfMySelf(&edgeId,&edgeId+1,true)));
9993 if(cellIdInMesh1DSplitRelative<0)
9994 cur1D->changeOrientationOfCells();
9995 const int *c1D(cur1D->getNodalConnectivity()->begin());
9996 const INTERP_KERNEL::CellModel& ref1DType(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c1D[0]));
9997 for(const int *it=candidatesIn2DBg;it!=candidatesIn2DEnd;it++)
9999 MCAuto<MEDCouplingUMesh> cur2D(static_cast<MEDCouplingUMesh *>(mesh2DSplit->buildPartOfMySelf(it,it+1,true)));
10000 const int *c(cur2D->getNodalConnectivity()->begin()),*ci(cur2D->getNodalConnectivityIndex()->begin());
10001 const INTERP_KERNEL::CellModel &cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[0]]));
10002 unsigned sz(cm.getNumberOfSons2(c+ci[0]+1,ci[1]-ci[0]-1));
10003 INTERP_KERNEL::AutoPtr<int> tmpPtr(new int[ci[1]-ci[0]]);
10004 for(unsigned it2=0;it2<sz;it2++)
10006 INTERP_KERNEL::NormalizedCellType typeOfSon;
10007 cm.fillSonCellNodalConnectivity2(it2,c+ci[0]+1,ci[1]-ci[0]-1,tmpPtr,typeOfSon);
10008 const INTERP_KERNEL::CellModel &curCM(INTERP_KERNEL::CellModel::GetCellModel(typeOfSon));
10009 if(AreEdgeEqual(coo,ref1DType,c1D+1,curCM,tmpPtr,eps))
10013 throw INTERP_KERNEL::Exception("FindRightCandidateAmong : internal error 2 ! Unable to find the edge among split cell !");
10019 * Partitions the first given 2D mesh using the second given 1D mesh as a tool.
10020 * 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
10021 * and finaly, in case of quadratic polygon the centers of edges new nodes.
10022 * The meshes should be in 2D space. In addition, returns two arrays mapping cells of the resulting mesh to cells of the input.
10024 * \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
10025 * 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)
10026 * \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
10027 * you can invoke orderConsecutiveCells1D on \a mesh1D.
10028 * \param [in] eps - precision used to perform intersections and localization operations.
10029 * \param [out] splitMesh2D - the result of the split of \a mesh2D mesh.
10030 * \param [out] splitMesh1D - the result of the split of \a mesh1D mesh.
10031 * \param [out] cellIdInMesh2D - the array that gives for each cell id \a i in \a splitMesh2D the id in \a mesh2D it comes from.
10032 * 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.
10033 * \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
10034 * and the cell in \a splitMesh2D on the right for the 2nt component. -1 means no cell.
10035 * 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.
10037 * \sa Intersect2DMeshes, orderConsecutiveCells1D, conformize2D, mergeNodes
10039 void MEDCouplingUMesh::Intersect2DMeshWith1DLine(const MEDCouplingUMesh *mesh2D, const MEDCouplingUMesh *mesh1D, double eps, MEDCouplingUMesh *&splitMesh2D, MEDCouplingUMesh *&splitMesh1D, DataArrayInt *&cellIdInMesh2D, DataArrayInt *&cellIdInMesh1D)
10041 if(!mesh2D || !mesh1D)
10042 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshWith1DLine : input meshes must be not NULL !");
10043 mesh2D->checkFullyDefined();
10044 mesh1D->checkFullyDefined();
10045 const std::vector<std::string>& compNames(mesh2D->getCoords()->getInfoOnComponents());
10046 if(mesh2D->getMeshDimension()!=2 || mesh2D->getSpaceDimension()!=2 || mesh1D->getMeshDimension()!=1 || mesh1D->getSpaceDimension()!=2)
10047 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshWith1DLine works with mesh2D with spacedim=meshdim=2 and mesh1D with meshdim=1 spaceDim=2 !");
10048 // Step 1: compute all edge intersections (new nodes)
10049 std::vector< std::vector<int> > intersectEdge1, colinear2, subDiv2;
10050 std::vector<double> addCoo,addCoordsQuadratic; // coordinates of newly created nodes
10051 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10052 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10054 // Build desc connectivity
10055 DataArrayInt *desc1(DataArrayInt::New()),*descIndx1(DataArrayInt::New()),*revDesc1(DataArrayInt::New()),*revDescIndx1(DataArrayInt::New());
10056 MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(revDesc1),dd4(revDescIndx1);
10057 MCAuto<MEDCouplingUMesh> m1Desc(mesh2D->buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1));
10058 std::map<int,int> mergedNodes;
10059 Intersect1DMeshes(m1Desc,mesh1D,eps,intersectEdge1,colinear2,subDiv2,addCoo,mergedNodes);
10060 // use mergeNodes to fix intersectEdge1
10061 for(std::vector< std::vector<int> >::iterator it0=intersectEdge1.begin();it0!=intersectEdge1.end();it0++)
10063 std::size_t n((*it0).size()/2);
10064 int eltStart((*it0)[0]),eltEnd((*it0)[2*n-1]);
10065 std::map<int,int>::const_iterator it1;
10066 it1=mergedNodes.find(eltStart);
10067 if(it1!=mergedNodes.end())
10068 (*it0)[0]=(*it1).second;
10069 it1=mergedNodes.find(eltEnd);
10070 if(it1!=mergedNodes.end())
10071 (*it0)[2*n-1]=(*it1).second;
10074 MCAuto<DataArrayDouble> addCooDa(DataArrayDouble::New());
10075 addCooDa->useArray(&addCoo[0],false,C_DEALLOC,(int)addCoo.size()/2,2);
10076 // Step 2: re-order newly created nodes according to the ordering found in m2
10077 std::vector< std::vector<int> > intersectEdge2;
10078 BuildIntersectEdges(m1Desc,mesh1D,addCoo,subDiv2,intersectEdge2);
10080 // Step 3: compute splitMesh1D
10081 MCAuto<DataArrayInt> idsInRet1Colinear,idsInDescMesh2DForIdsInRetColinear;
10082 MCAuto<DataArrayInt> ret2(DataArrayInt::New()); ret2->alloc(0,1);
10083 MCAuto<MEDCouplingUMesh> ret1(BuildMesh1DCutFrom(mesh1D,intersectEdge2,mesh2D->getCoords(),addCoo,mergedNodes,colinear2,intersectEdge1,
10084 idsInRet1Colinear,idsInDescMesh2DForIdsInRetColinear));
10085 MCAuto<DataArrayInt> ret3(DataArrayInt::New()); ret3->alloc(ret1->getNumberOfCells()*2,1); ret3->fillWithValue(std::numeric_limits<int>::max()); ret3->rearrange(2);
10086 MCAuto<DataArrayInt> idsInRet1NotColinear(idsInRet1Colinear->buildComplement(ret1->getNumberOfCells()));
10087 // deal with cells in mesh2D that are not cut but only some of their edges are
10088 MCAuto<DataArrayInt> idsInDesc2DToBeRefined(idsInDescMesh2DForIdsInRetColinear->deepCopy());
10089 idsInDesc2DToBeRefined->abs(); idsInDesc2DToBeRefined->applyLin(1,-1);
10090 idsInDesc2DToBeRefined=idsInDesc2DToBeRefined->buildUnique();
10091 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
10092 if(!idsInDesc2DToBeRefined->empty())
10094 DataArrayInt *out0(0),*outi0(0);
10095 MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
10096 MCAuto<DataArrayInt> outi0s(outi0);
10098 out0s=out0s->buildUnique();
10102 MCAuto<MEDCouplingUMesh> ret1NonCol(static_cast<MEDCouplingUMesh *>(ret1->buildPartOfMySelf(idsInRet1NotColinear->begin(),idsInRet1NotColinear->end())));
10103 MCAuto<DataArrayDouble> baryRet1(ret1NonCol->computeCellCenterOfMass());
10104 MCAuto<DataArrayInt> elts,eltsIndex;
10105 mesh2D->getCellsContainingPoints(baryRet1->begin(),baryRet1->getNumberOfTuples(),eps,elts,eltsIndex);
10106 MCAuto<DataArrayInt> eltsIndex2(eltsIndex->deltaShiftIndex());
10107 MCAuto<DataArrayInt> eltsIndex3(eltsIndex2->findIdsEqual(1));
10108 if(eltsIndex2->count(0)+eltsIndex3->getNumberOfTuples()!=ret1NonCol->getNumberOfCells())
10109 throw INTERP_KERNEL::Exception("Intersect2DMeshWith1DLine : internal error 1 !");
10110 MCAuto<DataArrayInt> cellsToBeModified(elts->buildUnique());
10111 MCAuto<DataArrayInt> untouchedCells(cellsToBeModified->buildComplement(mesh2D->getNumberOfCells()));
10112 if((DataArrayInt *)out0s)
10113 untouchedCells=untouchedCells->buildSubstraction(out0s);//if some edges in ret1 are colinear to descending mesh of mesh2D remove cells from untouched one
10114 std::vector< MCAuto<MEDCouplingUMesh> > outMesh2DSplit;
10115 // OK all is ready to insert in ret2 mesh
10116 if(!untouchedCells->empty())
10117 {// the most easy part, cells in mesh2D not impacted at all
10118 outMesh2DSplit.push_back(static_cast<MEDCouplingUMesh *>(mesh2D->buildPartOfMySelf(untouchedCells->begin(),untouchedCells->end())));
10119 outMesh2DSplit.back()->setCoords(ret1->getCoords());
10120 ret2->pushBackValsSilent(untouchedCells->begin(),untouchedCells->end());
10122 if((DataArrayInt *)out0s)
10123 {// here dealing with cells in out0s but not in cellsToBeModified
10124 MCAuto<DataArrayInt> fewModifiedCells(out0s->buildSubstraction(cellsToBeModified));
10125 const int *rdptr(dd3->begin()),*rdiptr(dd4->begin()),*dptr(dd1->begin()),*diptr(dd2->begin());
10126 for(const int *it=fewModifiedCells->begin();it!=fewModifiedCells->end();it++)
10128 outMesh2DSplit.push_back(BuildRefined2DCell(ret1->getCoords(),mesh2D,*it,dptr+diptr[*it],dptr+diptr[*it+1],intersectEdge1));
10129 ret1->setCoords(outMesh2DSplit.back()->getCoords());
10131 int offset(ret2->getNumberOfTuples());
10132 ret2->pushBackValsSilent(fewModifiedCells->begin(),fewModifiedCells->end());
10133 MCAuto<DataArrayInt> partOfRet3(DataArrayInt::New()); partOfRet3->alloc(2*idsInRet1Colinear->getNumberOfTuples(),1);
10134 partOfRet3->fillWithValue(std::numeric_limits<int>::max()); partOfRet3->rearrange(2);
10135 int kk(0),*ret3ptr(partOfRet3->getPointer());
10136 for(const int *it=idsInDescMesh2DForIdsInRetColinear->begin();it!=idsInDescMesh2DForIdsInRetColinear->end();it++,kk++)
10138 int faceId(std::abs(*it)-1);
10139 for(const int *it2=rdptr+rdiptr[faceId];it2!=rdptr+rdiptr[faceId+1];it2++)
10141 int tmp(fewModifiedCells->findIdFirstEqual(*it2));
10144 if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],-(*it))!=dptr+diptr[*it2+1])
10145 ret3ptr[2*kk]=tmp+offset;
10146 if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],(*it))!=dptr+diptr[*it2+1])
10147 ret3ptr[2*kk+1]=tmp+offset;
10150 {//the current edge is shared by a 2D cell that will be split just after
10151 if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],-(*it))!=dptr+diptr[*it2+1])
10152 ret3ptr[2*kk]=-(*it2+1);
10153 if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],(*it))!=dptr+diptr[*it2+1])
10154 ret3ptr[2*kk+1]=-(*it2+1);
10158 m1Desc->setCoords(ret1->getCoords());
10159 ret1NonCol->setCoords(ret1->getCoords());
10160 ret3->setPartOfValues3(partOfRet3,idsInRet1Colinear->begin(),idsInRet1Colinear->end(),0,2,1,true);
10161 if(!outMesh2DSplit.empty())
10163 DataArrayDouble *da(outMesh2DSplit.back()->getCoords());
10164 for(std::vector< MCAuto<MEDCouplingUMesh> >::iterator itt=outMesh2DSplit.begin();itt!=outMesh2DSplit.end();itt++)
10165 (*itt)->setCoords(da);
10168 cellsToBeModified=cellsToBeModified->buildUniqueNotSorted();
10169 for(const int *it=cellsToBeModified->begin();it!=cellsToBeModified->end();it++)
10171 MCAuto<DataArrayInt> idsNonColPerCell(elts->findIdsEqual(*it));
10172 idsNonColPerCell->transformWithIndArr(eltsIndex3->begin(),eltsIndex3->end());
10173 MCAuto<DataArrayInt> idsNonColPerCell2(idsInRet1NotColinear->selectByTupleId(idsNonColPerCell->begin(),idsNonColPerCell->end()));
10174 MCAuto<MEDCouplingUMesh> partOfMesh1CuttingCur2DCell(static_cast<MEDCouplingUMesh *>(ret1NonCol->buildPartOfMySelf(idsNonColPerCell->begin(),idsNonColPerCell->end())));
10175 MCAuto<DataArrayInt> partOfRet3;
10176 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));
10177 ret3->setPartOfValues3(partOfRet3,idsNonColPerCell2->begin(),idsNonColPerCell2->end(),0,2,1,true);
10178 outMesh2DSplit.push_back(splitOfOneCell);
10179 for(int i=0;i<splitOfOneCell->getNumberOfCells();i++)
10180 ret2->pushBackSilent(*it);
10183 std::size_t nbOfMeshes(outMesh2DSplit.size());
10184 std::vector<const MEDCouplingUMesh *> tmp(nbOfMeshes);
10185 for(std::size_t i=0;i<nbOfMeshes;i++)
10186 tmp[i]=outMesh2DSplit[i];
10188 ret1->getCoords()->setInfoOnComponents(compNames);
10189 MCAuto<MEDCouplingUMesh> ret2D(MEDCouplingUMesh::MergeUMeshesOnSameCoords(tmp));
10190 // To finish - filter ret3 - std::numeric_limits<int>::max() -> -1 - negate values must be resolved.
10191 ret3->rearrange(1);
10192 MCAuto<DataArrayInt> edgesToDealWith(ret3->findIdsStricltyNegative());
10193 for(const int *it=edgesToDealWith->begin();it!=edgesToDealWith->end();it++)
10195 int old2DCellId(-ret3->getIJ(*it,0)-1);
10196 MCAuto<DataArrayInt> candidates(ret2->findIdsEqual(old2DCellId));
10197 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
10199 ret3->changeValue(std::numeric_limits<int>::max(),-1);
10200 ret3->rearrange(2);
10202 splitMesh1D=ret1.retn();
10203 splitMesh2D=ret2D.retn();
10204 cellIdInMesh2D=ret2.retn();
10205 cellIdInMesh1D=ret3.retn();
10209 * Private. Third step of the partitioning algorithm (Intersect2DMeshes): reconstruct full 2D cells from the
10210 * (newly created) nodes corresponding to the edge intersections.
10212 * @param[out] cr, crI connectivity of the resulting mesh
10213 * @param[out] cNb1, cNb2 correspondance arrays giving for the merged mesh the initial cells IDs in m1 / m2
10214 * TODO: describe input parameters
10216 void MEDCouplingUMesh::BuildIntersecting2DCellsFromEdges(double eps, const MEDCouplingUMesh *m1, const int *desc1, const int *descIndx1,
10217 const std::vector<std::vector<int> >& intesctEdges1, const std::vector< std::vector<int> >& colinear2,
10218 const MEDCouplingUMesh *m2, const int *desc2, const int *descIndx2, const std::vector<std::vector<int> >& intesctEdges2,
10219 const std::vector<double>& addCoords,
10220 std::vector<double>& addCoordsQuadratic, std::vector<int>& cr, std::vector<int>& crI, std::vector<int>& cNb1, std::vector<int>& cNb2)
10222 static const int SPACEDIM=2;
10223 const double *coo1(m1->getCoords()->begin());
10224 const int *conn1(m1->getNodalConnectivity()->begin()),*connI1(m1->getNodalConnectivityIndex()->begin());
10225 int offset1(m1->getNumberOfNodes());
10226 const double *coo2(m2->getCoords()->begin());
10227 const int *conn2(m2->getNodalConnectivity()->begin()),*connI2(m2->getNodalConnectivityIndex()->begin());
10228 int offset2(offset1+m2->getNumberOfNodes());
10229 int offset3(offset2+((int)addCoords.size())/2);
10230 MCAuto<DataArrayDouble> bbox1Arr(m1->getBoundingBoxForBBTree()),bbox2Arr(m2->getBoundingBoxForBBTree());
10231 const double *bbox1(bbox1Arr->begin()),*bbox2(bbox2Arr->begin());
10232 // Here a BBTree on 2D-cells, not on segments:
10233 BBTree<SPACEDIM,int> myTree(bbox2,0,0,m2->getNumberOfCells(),eps);
10234 int ncell1(m1->getNumberOfCells());
10236 for(int i=0;i<ncell1;i++)
10238 std::vector<int> candidates2;
10239 myTree.getIntersectingElems(bbox1+i*2*SPACEDIM,candidates2);
10240 std::map<INTERP_KERNEL::Node *,int> mapp;
10241 std::map<int,INTERP_KERNEL::Node *> mappRev;
10242 INTERP_KERNEL::QuadraticPolygon pol1;
10243 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn1[connI1[i]];
10244 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
10245 // Populate mapp and mappRev with nodes from the current cell (i) from mesh1 - this also builds the Node* objects:
10246 MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,/* output */mapp,mappRev);
10247 // pol1 is the full cell from mesh2, in QP format, with all the additional intersecting nodes.
10248 pol1.buildFromCrudeDataArray(mappRev,cm.isQuadratic(),conn1+connI1[i]+1,coo1,
10249 desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1);
10251 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
10252 std::set<INTERP_KERNEL::Edge *> edgesBoundary2;// store all edges that are on boundary of (pol2 intersect pol1) minus edges on pol1.
10253 INTERP_KERNEL::IteratorOnComposedEdge it1(&pol1);
10254 for(it1.first();!it1.finished();it1.next())
10255 edges1.insert(it1.current()->getPtr());
10257 std::map<int,std::vector<INTERP_KERNEL::ElementaryEdge *> > edgesIn2ForShare; // common edges
10258 std::vector<INTERP_KERNEL::QuadraticPolygon> pol2s(candidates2.size());
10260 for(std::vector<int>::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++,ii++)
10262 INTERP_KERNEL::NormalizedCellType typ2=(INTERP_KERNEL::NormalizedCellType)conn2[connI2[*it2]];
10263 const INTERP_KERNEL::CellModel& cm2=INTERP_KERNEL::CellModel::GetCellModel(typ2);
10264 // Complete mapping with elements coming from the current cell it2 in mesh2:
10265 MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,/* output */mapp,mappRev);
10266 // pol2 is the new QP in the final merged result.
10267 pol2s[ii].buildFromCrudeDataArray2(mappRev,cm2.isQuadratic(),conn2+connI2[*it2]+1,coo2,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,
10268 pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2, /* output */ edgesIn2ForShare);
10271 for(std::vector<int>::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++,ii++)
10273 INTERP_KERNEL::ComposedEdge::InitLocationsWithOther(pol1,pol2s[ii]);
10274 pol2s[ii].updateLocOfEdgeFromCrudeDataArray2(desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2);
10275 //MEDCouplingUMeshAssignOnLoc(pol1,pol2,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,colinear2);
10276 pol1.buildPartitionsAbs(pol2s[ii],edges1,edgesBoundary2,mapp,i,*it2,offset3,addCoordsQuadratic,cr,crI,cNb1,cNb2);
10278 // Deals with remaining (non-consumed) edges from m1: these are the edges that were never touched
10279 // by m2 but that we still want to keep in the final result.
10280 if(!edges1.empty())
10284 INTERP_KERNEL::QuadraticPolygon::ComputeResidual(pol1,edges1,edgesBoundary2,mapp,offset3,i,addCoordsQuadratic,cr,crI,cNb1,cNb2);
10286 catch(INTERP_KERNEL::Exception& e)
10288 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();
10289 throw INTERP_KERNEL::Exception(oss.str());
10292 for(std::map<int,INTERP_KERNEL::Node *>::const_iterator it=mappRev.begin();it!=mappRev.end();it++)
10293 (*it).second->decrRef();
10298 * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
10299 * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
10300 * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
10301 * The caller is to deal with the resulting DataArrayInt.
10302 * \throw If the coordinate array is not set.
10303 * \throw If the nodal connectivity of the cells is not defined.
10304 * \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
10305 * \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
10307 * \sa DataArrayInt::sortEachPairToMakeALinkedList
10309 DataArrayInt *MEDCouplingUMesh::orderConsecutiveCells1D() const
10311 checkFullyDefined();
10312 if(getMeshDimension()!=1)
10313 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
10315 // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
10316 MCAuto<DataArrayInt> _d(DataArrayInt::New()),_dI(DataArrayInt::New());
10317 MCAuto<DataArrayInt> _rD(DataArrayInt::New()),_rDI(DataArrayInt::New());
10318 MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
10319 const int *d(_d->begin()), *dI(_dI->begin());
10320 const int *rD(_rD->begin()), *rDI(_rDI->begin());
10321 MCAuto<DataArrayInt> _dsi(_rDI->deltaShiftIndex());
10322 const int * dsi(_dsi->begin());
10323 MCAuto<DataArrayInt> dsii = _dsi->findIdsNotInRange(0,3);
10325 if (dsii->getNumberOfTuples())
10326 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
10328 int nc(getNumberOfCells());
10329 MCAuto<DataArrayInt> result(DataArrayInt::New());
10330 result->alloc(nc,1);
10332 // set of edges not used so far
10333 std::set<int> edgeSet;
10334 for (int i=0; i<nc; edgeSet.insert(i), i++);
10338 // while we have points with only one neighbor segments
10341 std::list<int> linePiece;
10342 // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
10343 for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
10345 // Fill the list forward (resp. backward) from the start segment:
10346 int activeSeg = startSeg;
10347 int prevPointId = -20;
10349 while (!edgeSet.empty())
10351 if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
10354 linePiece.push_back(activeSeg);
10356 linePiece.push_front(activeSeg);
10357 edgeSet.erase(activeSeg);
10360 int ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
10361 ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
10362 if (dsi[ptId] == 1) // hitting the end of the line
10364 prevPointId = ptId;
10365 int seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
10366 activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
10369 // Done, save final piece into DA:
10370 std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
10371 newIdx += linePiece.size();
10373 // identify next valid start segment (one which is not consumed)
10374 if(!edgeSet.empty())
10375 startSeg = *(edgeSet.begin());
10377 while (!edgeSet.empty());
10378 return result.retn();
10383 void IKGeo2DInternalMapper2(INTERP_KERNEL::Node *n, const std::map<MCAuto<INTERP_KERNEL::Node>,int>& m, int forbVal0, int forbVal1, std::vector<int>& isect)
10385 MCAuto<INTERP_KERNEL::Node> nTmp(n); nTmp->incrRef();
10386 std::map<MCAuto<INTERP_KERNEL::Node>,int>::const_iterator it(m.find(nTmp));
10388 throw INTERP_KERNEL::Exception("Internal error in remapping !");
10389 int v((*it).second);
10390 if(v==forbVal0 || v==forbVal1)
10392 if(std::find(isect.begin(),isect.end(),v)==isect.end())
10393 isect.push_back(v);
10396 bool IKGeo2DInternalMapper(const INTERP_KERNEL::ComposedEdge& c, const std::map<MCAuto<INTERP_KERNEL::Node>,int>& m, int forbVal0, int forbVal1, std::vector<int>& isect)
10401 bool presenceOfOn(false);
10402 for(int i=0;i<sz;i++)
10404 INTERP_KERNEL::ElementaryEdge *e(c[i]);
10405 if(e->getLoc()!=INTERP_KERNEL::FULL_ON_1)
10407 IKGeo2DInternalMapper2(e->getStartNode(),m,forbVal0,forbVal1,isect);
10408 IKGeo2DInternalMapper2(e->getEndNode(),m,forbVal0,forbVal1,isect);
10410 return presenceOfOn;
10416 * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
10417 * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
10418 * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
10419 * a minimal creation of new nodes is wanted.
10420 * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
10421 * nodes if a SEG3 is split without information of middle.
10422 * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
10423 * avoid to have a non conform mesh.
10425 * \return int - the number of new nodes created (in most of cases 0).
10427 * \throw If \a this is not coherent.
10428 * \throw If \a this has not spaceDim equal to 2.
10429 * \throw If \a this has not meshDim equal to 2.
10430 * \throw If some subcells needed to be split are orphan.
10431 * \sa MEDCouplingUMesh::conformize2D
10433 int MEDCouplingUMesh::split2DCells(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *midOpt, const DataArrayInt *midOptI)
10435 if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
10436 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
10437 desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
10438 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10439 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10440 if(midOpt==0 && midOptI==0)
10442 split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
10445 else if(midOpt!=0 && midOptI!=0)
10446 return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
10448 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
10452 * \b WARNING this method is \b potentially \b non \b const (if returned array is empty).
10453 * \b WARNING this method lead to have a non geometric type sorted mesh (for MED file users) !
10454 * 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
10455 * 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).
10456 * 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.
10458 * Whatever the returned value, this method does not alter the order of cells in \a this neither the orientation of cells.
10459 * The modified cells, if any, are systematically declared as NORM_POLYGON or NORM_QPOLYG depending on the initial quadraticness of geometric type.
10461 * This method expects that \b this has a meshDim equal 2 and spaceDim equal to 2 too.
10462 * This method expects that all nodes in \a this are not closer than \a eps.
10463 * If it is not the case you can invoke MEDCouplingUMesh::mergeNodes before calling this method.
10465 * \param [in] eps the relative error to detect merged edges.
10466 * \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
10467 * that the user is expected to deal with.
10469 * \throw If \a this is not coherent.
10470 * \throw If \a this has not spaceDim equal to 2.
10471 * \throw If \a this has not meshDim equal to 2.
10472 * \sa MEDCouplingUMesh::mergeNodes, MEDCouplingUMesh::split2DCells
10474 DataArrayInt *MEDCouplingUMesh::conformize2D(double eps)
10476 static const int SPACEDIM=2;
10477 checkConsistencyLight();
10478 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10479 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::conformize2D : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10480 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
10481 MCAuto<MEDCouplingUMesh> mDesc(buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));
10482 const int *c(mDesc->getNodalConnectivity()->begin()),*ci(mDesc->getNodalConnectivityIndex()->begin()),*rd(revDesc1->begin()),*rdi(revDescIndx1->begin());
10483 MCAuto<DataArrayDouble> bboxArr(mDesc->getBoundingBoxForBBTree());
10484 const double *bbox(bboxArr->begin()),*coords(getCoords()->begin());
10485 int nCell(getNumberOfCells()),nDescCell(mDesc->getNumberOfCells());
10486 std::vector< std::vector<int> > intersectEdge(nDescCell),overlapEdge(nDescCell);
10487 std::vector<double> addCoo;
10488 BBTree<SPACEDIM,int> myTree(bbox,0,0,nDescCell,-eps);
10489 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10490 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10491 for(int i=0;i<nDescCell;i++)
10493 std::vector<int> candidates;
10494 myTree.getIntersectingElems(bbox+i*2*SPACEDIM,candidates);
10495 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
10498 std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
10499 INTERP_KERNEL::Edge *e1(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coords,m)),
10500 *e2(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[*it]],c+ci[*it]+1,coords,m));
10501 INTERP_KERNEL::MergePoints merge;
10502 INTERP_KERNEL::QuadraticPolygon c1,c2;
10503 e1->intersectWith(e2,merge,c1,c2);
10504 e1->decrRef(); e2->decrRef();
10505 if(IKGeo2DInternalMapper(c1,m,c[ci[i]+1],c[ci[i]+2],intersectEdge[i]))
10506 overlapEdge[i].push_back(*it);
10507 if(IKGeo2DInternalMapper(c2,m,c[ci[*it]+1],c[ci[*it]+2],intersectEdge[*it]))
10508 overlapEdge[*it].push_back(i);
10511 // splitting done. sort intersect point in intersectEdge.
10512 std::vector< std::vector<int> > middle(nDescCell);
10513 int nbOf2DCellsToBeSplit(0);
10514 bool middleNeedsToBeUsed(false);
10515 std::vector<bool> cells2DToTreat(nDescCell,false);
10516 for(int i=0;i<nDescCell;i++)
10518 std::vector<int>& isect(intersectEdge[i]);
10519 int sz((int)isect.size());
10522 std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
10523 INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coords,m));
10524 e->sortSubNodesAbs(coords,isect);
10529 int idx0(rdi[i]),idx1(rdi[i+1]);
10531 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::conformize2D : internal error #0 !");
10532 if(!cells2DToTreat[rd[idx0]])
10534 cells2DToTreat[rd[idx0]]=true;
10535 nbOf2DCellsToBeSplit++;
10537 // try to reuse at most eventual 'middle' of SEG3
10538 std::vector<int>& mid(middle[i]);
10539 mid.resize(sz+1,-1);
10540 if((INTERP_KERNEL::NormalizedCellType)c[ci[i]]==INTERP_KERNEL::NORM_SEG3)
10542 middleNeedsToBeUsed=true;
10543 const std::vector<int>& candidates(overlapEdge[i]);
10544 std::vector<int> trueCandidates;
10545 for(std::vector<int>::const_iterator itc=candidates.begin();itc!=candidates.end();itc++)
10546 if((INTERP_KERNEL::NormalizedCellType)c[ci[*itc]]==INTERP_KERNEL::NORM_SEG3)
10547 trueCandidates.push_back(*itc);
10548 int stNode(c[ci[i]+1]),endNode(isect[0]);
10549 for(int j=0;j<sz+1;j++)
10551 for(std::vector<int>::const_iterator itc=trueCandidates.begin();itc!=trueCandidates.end();itc++)
10553 int tmpSt(c[ci[*itc]+1]),tmpEnd(c[ci[*itc]+2]);
10554 if((tmpSt==stNode && tmpEnd==endNode) || (tmpSt==endNode && tmpEnd==stNode))
10555 { mid[j]=*itc; break; }
10558 endNode=j<sz-1?isect[j+1]:c[ci[i]+2];
10563 MCAuto<DataArrayInt> ret(DataArrayInt::New()),notRet(DataArrayInt::New()); ret->alloc(nbOf2DCellsToBeSplit,1);
10564 if(nbOf2DCellsToBeSplit==0)
10567 int *retPtr(ret->getPointer());
10568 for(int i=0;i<nCell;i++)
10569 if(cells2DToTreat[i])
10572 MCAuto<DataArrayInt> mSafe,nSafe,oSafe,pSafe,qSafe,rSafe;
10573 DataArrayInt *m(0),*n(0),*o(0),*p(0),*q(0),*r(0);
10574 MEDCouplingUMesh::ExtractFromIndexedArrays(ret->begin(),ret->end(),desc1,descIndx1,m,n); mSafe=m; nSafe=n;
10575 DataArrayInt::PutIntoToSkylineFrmt(intersectEdge,o,p); oSafe=o; pSafe=p;
10576 if(middleNeedsToBeUsed)
10577 { DataArrayInt::PutIntoToSkylineFrmt(middle,q,r); qSafe=q; rSafe=r; }
10578 MCAuto<MEDCouplingUMesh> modif(static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(ret->begin(),ret->end(),true)));
10579 int nbOfNodesCreated(modif->split2DCells(mSafe,nSafe,oSafe,pSafe,qSafe,rSafe));
10580 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.
10581 setPartOfMySelf(ret->begin(),ret->end(),*modif);
10583 bool areNodesMerged; int newNbOfNodes;
10584 if(nbOfNodesCreated!=0)
10585 MCAuto<DataArrayInt> tmp(mergeNodes(eps,areNodesMerged,newNbOfNodes));
10591 * 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.
10592 * 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).
10593 * 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
10594 * to invoke MEDCouplingUMesh::mergeNodes and MEDCouplingUMesh::conformize2D right after this call.
10595 * 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
10596 * new nodes for center of merged edges is are systematically created and appended at the end of the previously existing nodes.
10598 * 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
10599 * using new instance, idem for coordinates.
10601 * 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.
10603 * \return DataArrayInt * - The list of cellIds in \a this that have at least one edge colinearized.
10605 * \throw If \a this is not coherent.
10606 * \throw If \a this has not spaceDim equal to 2.
10607 * \throw If \a this has not meshDim equal to 2.
10609 * \sa MEDCouplingUMesh::conformize2D, MEDCouplingUMesh::mergeNodes, MEDCouplingUMesh::convexEnvelop2D.
10611 DataArrayInt *MEDCouplingUMesh::colinearize2D(double eps)
10613 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
10614 checkConsistencyLight();
10615 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10616 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::colinearize2D : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10617 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10618 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10619 int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
10620 const int *cptr(_nodal_connec->begin()),*ciptr(_nodal_connec_index->begin());
10621 MCAuto<DataArrayInt> newc(DataArrayInt::New()),newci(DataArrayInt::New()); newci->alloc(nbOfCells+1,1); newc->alloc(0,1); newci->setIJ(0,0,0);
10622 MCAuto<DataArrayDouble> appendedCoords(DataArrayDouble::New()); appendedCoords->alloc(0,1);//1 not 2 it is not a bug.
10623 const double *coords(_coords->begin());
10624 int *newciptr(newci->getPointer());
10625 for(int i=0;i<nbOfCells;i++,newciptr++,ciptr++)
10627 if(Colinearize2DCell(coords,cptr+ciptr[0],cptr+ciptr[1],nbOfNodes,newc,appendedCoords))
10628 ret->pushBackSilent(i);
10629 newciptr[1]=newc->getNumberOfTuples();
10634 if(!appendedCoords->empty())
10636 appendedCoords->rearrange(2);
10637 MCAuto<DataArrayDouble> newCoords(DataArrayDouble::Aggregate(getCoords(),appendedCoords));//treat info on components
10639 setCoords(newCoords);
10642 setConnectivity(newc,newci,true);
10647 * \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.
10648 * 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.
10649 * And for each j in [1,n) intersect[i][2*(j-1)+1]==intersect[i][2*j].
10650 * \param [out] subDiv2 - for each cell in \a m2Desc returns nodes that split it using convention \a m1Desc first, then \a m2Desc, then addCoo
10651 * \param [out] colinear2 - for each cell in \a m2Desc returns the edges in \a m1Desc that are colinear to it.
10652 * \param [out] addCoo - nodes to be append at the end
10653 * \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.
10655 void MEDCouplingUMesh::Intersect1DMeshes(const MEDCouplingUMesh *m1Desc, const MEDCouplingUMesh *m2Desc, double eps,
10656 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)
10658 static const int SPACEDIM=2;
10659 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10660 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10661 const int *c1(m1Desc->getNodalConnectivity()->begin()),*ci1(m1Desc->getNodalConnectivityIndex()->begin());
10662 // Build BB tree of all edges in the tool mesh (second mesh)
10663 MCAuto<DataArrayDouble> bbox1Arr(m1Desc->getBoundingBoxForBBTree()),bbox2Arr(m2Desc->getBoundingBoxForBBTree());
10664 const double *bbox1(bbox1Arr->begin()),*bbox2(bbox2Arr->begin());
10665 int nDescCell1(m1Desc->getNumberOfCells()),nDescCell2(m2Desc->getNumberOfCells());
10666 intersectEdge1.resize(nDescCell1);
10667 colinear2.resize(nDescCell2);
10668 subDiv2.resize(nDescCell2);
10669 BBTree<SPACEDIM,int> myTree(bbox2,0,0,m2Desc->getNumberOfCells(),-eps);
10671 std::vector<int> candidates1(1);
10672 int offset1(m1Desc->getNumberOfNodes());
10673 int offset2(offset1+m2Desc->getNumberOfNodes());
10674 for(int i=0;i<nDescCell1;i++) // for all edges in the first mesh
10676 std::vector<int> candidates2; // edges of mesh2 candidate for intersection
10677 myTree.getIntersectingElems(bbox1+i*2*SPACEDIM,candidates2);
10678 if(!candidates2.empty()) // candidates2 holds edges from the second mesh potentially intersecting current edge i in mesh1
10680 std::map<INTERP_KERNEL::Node *,int> map1,map2;
10681 // pol2 is not necessarily a closed polygon: just a set of (quadratic) edges (same as candidates2) in the Geometric DS format
10682 INTERP_KERNEL::QuadraticPolygon *pol2=MEDCouplingUMeshBuildQPFromMesh(m2Desc,candidates2,map2);
10684 INTERP_KERNEL::QuadraticPolygon *pol1=MEDCouplingUMeshBuildQPFromMesh(m1Desc,candidates1,map1);
10685 // 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
10686 // This trick guarantees that Node * are discriminant (i.e. form a unique identifier)
10687 std::set<INTERP_KERNEL::Node *> nodes;
10688 pol1->getAllNodes(nodes); pol2->getAllNodes(nodes);
10689 std::size_t szz(nodes.size());
10690 std::vector< MCAuto<INTERP_KERNEL::Node> > nodesSafe(szz);
10691 std::set<INTERP_KERNEL::Node *>::const_iterator itt(nodes.begin());
10692 for(std::size_t iii=0;iii<szz;iii++,itt++)
10693 { (*itt)->incrRef(); nodesSafe[iii]=*itt; }
10694 // end of protection
10695 // Performs egde cutting:
10696 pol1->splitAbs(*pol2,map1,map2,offset1,offset2,candidates2,intersectEdge1[i],i,colinear2,subDiv2,addCoo,mergedNodes);
10701 // Copy the edge (take only the two first points, ie discard quadratic point at this stage)
10702 intersectEdge1[i].insert(intersectEdge1[i].end(),c1+ci1[i]+1,c1+ci1[i]+3);
10707 * This method is private and is the first step of Partition of 2D mesh (spaceDim==2 and meshDim==2).
10708 * It builds the descending connectivity of the two meshes, and then using a binary tree
10709 * it computes the edge intersections. This results in new points being created : they're stored in addCoo.
10710 * Documentation about parameters colinear2 and subDiv2 can be found in method QuadraticPolygon::splitAbs().
10712 void MEDCouplingUMesh::IntersectDescending2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2, double eps,
10713 std::vector< std::vector<int> >& intersectEdge1, std::vector< std::vector<int> >& colinear2, std::vector< std::vector<int> >& subDiv2,
10714 MEDCouplingUMesh *& m1Desc, DataArrayInt *&desc1, DataArrayInt *&descIndx1, DataArrayInt *&revDesc1, DataArrayInt *&revDescIndx1,
10715 std::vector<double>& addCoo,
10716 MEDCouplingUMesh *& m2Desc, DataArrayInt *&desc2, DataArrayInt *&descIndx2, DataArrayInt *&revDesc2, DataArrayInt *&revDescIndx2)
10718 // Build desc connectivity
10719 desc1=DataArrayInt::New(); descIndx1=DataArrayInt::New(); revDesc1=DataArrayInt::New(); revDescIndx1=DataArrayInt::New();
10720 desc2=DataArrayInt::New();
10721 descIndx2=DataArrayInt::New();
10722 revDesc2=DataArrayInt::New();
10723 revDescIndx2=DataArrayInt::New();
10724 MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(revDesc1),dd4(revDescIndx1);
10725 MCAuto<DataArrayInt> dd5(desc2),dd6(descIndx2),dd7(revDesc2),dd8(revDescIndx2);
10726 m1Desc=m1->buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1);
10727 m2Desc=m2->buildDescendingConnectivity2(desc2,descIndx2,revDesc2,revDescIndx2);
10728 MCAuto<MEDCouplingUMesh> dd9(m1Desc),dd10(m2Desc);
10729 std::map<int,int> notUsedMap;
10730 Intersect1DMeshes(m1Desc,m2Desc,eps,intersectEdge1,colinear2,subDiv2,addCoo,notUsedMap);
10731 m1Desc->incrRef(); desc1->incrRef(); descIndx1->incrRef(); revDesc1->incrRef(); revDescIndx1->incrRef();
10732 m2Desc->incrRef(); desc2->incrRef(); descIndx2->incrRef(); revDesc2->incrRef(); revDescIndx2->incrRef();
10736 * This method performs the 2nd step of Partition of 2D mesh.
10737 * This method has 4 inputs :
10738 * - a mesh 'm1' with meshDim==1 and a SpaceDim==2
10739 * - a mesh 'm2' with meshDim==1 and a SpaceDim==2
10740 * - subDiv of size 'm2->getNumberOfCells()' that lists for each seg cell in 'm' the splitting node ids randomly sorted.
10741 * 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'
10742 * Nodes end up lying consecutively on a cutted edge.
10743 * \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.
10744 * (Only present for its coords in case of 'subDiv' shares some nodes of 'm1')
10745 * \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.
10746 * \param addCoo input parameter with additional nodes linked to intersection of the 2 meshes.
10747 * \param[out] intersectEdge the same content as subDiv, but correclty oriented.
10749 void MEDCouplingUMesh::BuildIntersectEdges(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2,
10750 const std::vector<double>& addCoo,
10751 const std::vector< std::vector<int> >& subDiv, std::vector< std::vector<int> >& intersectEdge)
10753 int offset1=m1->getNumberOfNodes();
10754 int ncell=m2->getNumberOfCells();
10755 const int *c=m2->getNodalConnectivity()->begin();
10756 const int *cI=m2->getNodalConnectivityIndex()->begin();
10757 const double *coo=m2->getCoords()->begin();
10758 const double *cooBis=m1->getCoords()->begin();
10759 int offset2=offset1+m2->getNumberOfNodes();
10760 intersectEdge.resize(ncell);
10761 for(int i=0;i<ncell;i++,cI++)
10763 const std::vector<int>& divs=subDiv[i];
10764 int nnode=cI[1]-cI[0]-1;
10765 std::map<int, std::pair<INTERP_KERNEL::Node *,bool> > mapp2;
10766 std::map<INTERP_KERNEL::Node *, int> mapp22;
10767 for(int j=0;j<nnode;j++)
10769 INTERP_KERNEL::Node *nn=new INTERP_KERNEL::Node(coo[2*c[(*cI)+j+1]],coo[2*c[(*cI)+j+1]+1]);
10770 int nnid=c[(*cI)+j+1];
10771 mapp2[nnid]=std::pair<INTERP_KERNEL::Node *,bool>(nn,true);
10772 mapp22[nn]=nnid+offset1;
10774 INTERP_KERNEL::Edge *e=MEDCouplingUMeshBuildQPFromEdge((INTERP_KERNEL::NormalizedCellType)c[*cI],mapp2,c+(*cI)+1);
10775 for(std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >::const_iterator it=mapp2.begin();it!=mapp2.end();it++)
10776 ((*it).second.first)->decrRef();
10777 std::vector<INTERP_KERNEL::Node *> addNodes(divs.size());
10778 std::map<INTERP_KERNEL::Node *,int> mapp3;
10779 for(std::size_t j=0;j<divs.size();j++)
10782 INTERP_KERNEL::Node *tmp=0;
10784 tmp=new INTERP_KERNEL::Node(cooBis[2*id],cooBis[2*id+1]);
10785 else if(id<offset2)
10786 tmp=new INTERP_KERNEL::Node(coo[2*(id-offset1)],coo[2*(id-offset1)+1]);//if it happens, bad news mesh 'm2' is non conform.
10788 tmp=new INTERP_KERNEL::Node(addCoo[2*(id-offset2)],addCoo[2*(id-offset2)+1]);
10792 e->sortIdsAbs(addNodes,mapp22,mapp3,intersectEdge[i]);
10793 for(std::vector<INTERP_KERNEL::Node *>::const_iterator it=addNodes.begin();it!=addNodes.end();it++)
10800 * 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).
10801 * 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
10802 * with a plane. The result will be put in 'cut3DSuf' out parameter.
10803 * \param [in] cut3DCurve input paramter that gives for each 3DCurve cell if it owns fully to the plane or partially.
10804 * \param [out] nodesOnPlane, returns all the nodes that are on the plane.
10805 * \param [in] nodal3DSurf is the nodal connectivity of 3D surf mesh.
10806 * \param [in] nodalIndx3DSurf is the nodal connectivity index of 3D surf mesh.
10807 * \param [in] nodal3DCurve is the nodal connectivity of 3D curve mesh.
10808 * \param [in] nodal3DIndxCurve is the nodal connectivity index of 3D curve mesh.
10809 * \param [in] desc is the descending connectivity 3DSurf->3DCurve
10810 * \param [in] descIndx is the descending connectivity index 3DSurf->3DCurve
10811 * \param [out] cut3DSuf input/output param.
10813 void MEDCouplingUMesh::AssemblyForSplitFrom3DCurve(const std::vector<int>& cut3DCurve, std::vector<int>& nodesOnPlane, const int *nodal3DSurf, const int *nodalIndx3DSurf,
10814 const int *nodal3DCurve, const int *nodalIndx3DCurve,
10815 const int *desc, const int *descIndx,
10816 std::vector< std::pair<int,int> >& cut3DSurf)
10818 std::set<int> nodesOnP(nodesOnPlane.begin(),nodesOnPlane.end());
10819 int nbOf3DSurfCell=(int)cut3DSurf.size();
10820 for(int i=0;i<nbOf3DSurfCell;i++)
10822 std::vector<int> res;
10823 int offset=descIndx[i];
10824 int nbOfSeg=descIndx[i+1]-offset;
10825 for(int j=0;j<nbOfSeg;j++)
10827 int edgeId=desc[offset+j];
10828 int status=cut3DCurve[edgeId];
10832 res.push_back(status);
10835 res.push_back(nodal3DCurve[nodalIndx3DCurve[edgeId]+1]);
10836 res.push_back(nodal3DCurve[nodalIndx3DCurve[edgeId]+2]);
10844 cut3DSurf[i].first=res[0]; cut3DSurf[i].second=res[1];
10850 std::set<int> s1(nodal3DSurf+nodalIndx3DSurf[i]+1,nodal3DSurf+nodalIndx3DSurf[i+1]);
10851 std::set_intersection(nodesOnP.begin(),nodesOnP.end(),s1.begin(),s1.end(),std::back_insert_iterator< std::vector<int> >(res));
10854 cut3DSurf[i].first=res[0]; cut3DSurf[i].second=res[1];
10858 cut3DSurf[i].first=-1; cut3DSurf[i].second=-1;
10863 {// case when plane is on a multi colinear edge of a polyhedron
10864 if((int)res.size()==2*nbOfSeg)
10866 cut3DSurf[i].first=-2; cut3DSurf[i].second=i;
10869 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AssemblyPointsFrom3DCurve : unexpected situation !");
10876 * \a this is expected to be a mesh with spaceDim==3 and meshDim==3. If not an exception will be thrown.
10877 * 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).
10878 * 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
10879 * with a plane. The result will be put in 'nodalRes' 'nodalResIndx' and 'cellIds' out parameters.
10880 * \param cut3DSurf input paramter that gives for each 3DSurf its intersection with plane (result of MEDCouplingUMesh::AssemblyForSplitFrom3DCurve).
10881 * \param desc is the descending connectivity 3D->3DSurf
10882 * \param descIndx is the descending connectivity index 3D->3DSurf
10884 void MEDCouplingUMesh::assemblyForSplitFrom3DSurf(const std::vector< std::pair<int,int> >& cut3DSurf,
10885 const int *desc, const int *descIndx,
10886 DataArrayInt *nodalRes, DataArrayInt *nodalResIndx, DataArrayInt *cellIds) const
10888 checkFullyDefined();
10889 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
10890 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::assemblyForSplitFrom3DSurf works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
10891 const int *nodal3D(_nodal_connec->begin()),*nodalIndx3D(_nodal_connec_index->begin());
10892 int nbOfCells(getNumberOfCells());
10893 for(int i=0;i<nbOfCells;i++)
10895 std::map<int, std::set<int> > m;
10896 int offset=descIndx[i];
10897 int nbOfFaces=descIndx[i+1]-offset;
10900 for(int j=0;j<nbOfFaces;j++)
10902 const std::pair<int,int>& p=cut3DSurf[desc[offset+j]];
10903 if(p.first!=-1 && p.second!=-1)
10907 start=p.first; end=p.second;
10908 m[p.first].insert(p.second);
10909 m[p.second].insert(p.first);
10913 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodal3D[nodalIndx3D[i]]);
10914 int sz=nodalIndx3D[i+1]-nodalIndx3D[i]-1;
10915 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
10916 INTERP_KERNEL::NormalizedCellType cmsId;
10917 unsigned nbOfNodesSon=cm.fillSonCellNodalConnectivity2(j,nodal3D+nodalIndx3D[i]+1,sz,tmp,cmsId);
10918 start=tmp[0]; end=tmp[nbOfNodesSon-1];
10919 for(unsigned k=0;k<nbOfNodesSon;k++)
10921 m[tmp[k]].insert(tmp[(k+1)%nbOfNodesSon]);
10922 m[tmp[(k+1)%nbOfNodesSon]].insert(tmp[k]);
10929 std::vector<int> conn(1,(int)INTERP_KERNEL::NORM_POLYGON);
10933 std::map<int, std::set<int> >::const_iterator it=m.find(start);
10934 const std::set<int>& s=(*it).second;
10935 std::set<int> s2; s2.insert(prev);
10937 std::set_difference(s.begin(),s.end(),s2.begin(),s2.end(),inserter(s3,s3.begin()));
10940 int val=*s3.begin();
10941 conn.push_back(start);
10948 conn.push_back(end);
10951 nodalRes->insertAtTheEnd(conn.begin(),conn.end());
10952 nodalResIndx->pushBackSilent(nodalRes->getNumberOfTuples());
10953 cellIds->pushBackSilent(i);
10958 void InsertNodeInConnIfNecessary(int nodeIdToInsert, std::vector<int>& conn, const double *coords, double eps)
10960 std::vector<int>::iterator it(std::find(conn.begin(),conn.end(),nodeIdToInsert));
10963 std::size_t sz(conn.size());
10964 std::size_t found(std::numeric_limits<std::size_t>::max());
10965 for(std::size_t i=0;i<sz;i++)
10967 int pt0(conn[i]),pt1(conn[(i+1)%sz]);
10968 double v1[3]={coords[3*pt1+0]-coords[3*pt0+0],coords[3*pt1+1]-coords[3*pt0+1],coords[3*pt1+2]-coords[3*pt0+2]},v2[3]={coords[3*nodeIdToInsert+0]-coords[3*pt0+0],coords[3*nodeIdToInsert+1]-coords[3*pt0+1],coords[3*nodeIdToInsert+2]-coords[3*pt0+2]};
10969 double normm(sqrt(v1[0]*v1[0]+v1[1]*v1[1]+v1[2]*v1[2]));
10970 std::transform(v1,v1+3,v1,std::bind2nd(std::multiplies<double>(),1./normm));
10971 std::transform(v2,v2+3,v2,std::bind2nd(std::multiplies<double>(),1./normm));
10973 v3[0]=v1[1]*v2[2]-v1[2]*v2[1]; v3[1]=v1[2]*v2[0]-v1[0]*v2[2]; v3[2]=v1[0]*v2[1]-v1[1]*v2[0];
10974 double normm2(sqrt(v3[0]*v3[0]+v3[1]*v3[1]+v3[2]*v3[2])),dotTest(v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2]);
10976 if(dotTest>eps && dotTest<1.-eps)
10982 if(found==std::numeric_limits<std::size_t>::max())
10983 throw INTERP_KERNEL::Exception("InsertNodeInConnIfNecessary : not found point !");
10984 conn.insert(conn.begin()+(found+1)%sz,nodeIdToInsert);
10987 void SplitIntoToPart(const std::vector<int>& conn, int pt0, int pt1, std::vector<int>& part0, std::vector<int>& part1)
10989 std::size_t sz(conn.size());
10990 std::vector<int> *curPart(&part0);
10991 for(std::size_t i=0;i<sz;i++)
10993 int nextt(conn[(i+1)%sz]);
10994 (*curPart).push_back(nextt);
10995 if(nextt==pt0 || nextt==pt1)
10997 if(curPart==&part0)
11001 (*curPart).push_back(nextt);
11007 * this method method splits cur cells 3D Surf in sub cells 3DSurf using the previous subsplit. This method is the last one used to clip.
11009 void MEDCouplingUMesh::buildSubCellsFromCut(const std::vector< std::pair<int,int> >& cut3DSurf,
11010 const int *desc, const int *descIndx, const double *coords, double eps,
11011 std::vector<std::vector<int> >& res) const
11013 checkFullyDefined();
11014 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
11015 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSubCellsFromCut works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
11016 const int *nodal3D(_nodal_connec->begin()),*nodalIndx3D(_nodal_connec_index->begin());
11017 int nbOfCells(getNumberOfCells());
11019 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSubCellsFromCut works only with single cell presently !");
11020 for(int i=0;i<nbOfCells;i++)
11022 int offset(descIndx[i]),nbOfFaces(descIndx[i+1]-offset),start(-1),end(-1);
11023 for(int j=0;j<nbOfFaces;j++)
11025 const std::pair<int,int>& p=cut3DSurf[desc[offset+j]];
11026 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodal3D[nodalIndx3D[i]]));
11027 int sz=nodalIndx3D[i+1]-nodalIndx3D[i]-1;
11028 INTERP_KERNEL::AutoPtr<int> tmp(new int[sz]);
11029 INTERP_KERNEL::NormalizedCellType cmsId;
11030 unsigned nbOfNodesSon(cm.fillSonCellNodalConnectivity2(j,nodal3D+nodalIndx3D[i]+1,sz,tmp,cmsId));
11031 std::vector<int> elt((int *)tmp,(int *)tmp+nbOfNodesSon);
11032 if(p.first!=-1 && p.second!=-1)
11036 InsertNodeInConnIfNecessary(p.first,elt,coords,eps);
11037 InsertNodeInConnIfNecessary(p.second,elt,coords,eps);
11038 std::vector<int> elt1,elt2;
11039 SplitIntoToPart(elt,p.first,p.second,elt1,elt2);
11040 res.push_back(elt1);
11041 res.push_back(elt2);
11044 res.push_back(elt);
11047 res.push_back(elt);
11053 * 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
11054 * 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
11055 * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
11056 * 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
11057 * 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.
11059 * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
11061 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const int *nodalConnBg, const int *nodalConnEnd, DataArrayInt *nodalConnecOut)
11063 std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
11066 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
11067 if(cm.getDimension()==2)
11069 const int *node=nodalConnBg+1;
11070 int startNode=*node++;
11071 double refX=coords[2*startNode];
11072 for(;node!=nodalConnEnd;node++)
11074 if(coords[2*(*node)]<refX)
11077 refX=coords[2*startNode];
11080 std::vector<int> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
11084 double angle0=-M_PI/2;
11089 double angleNext=0.;
11090 while(nextNode!=startNode)
11094 for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
11096 if(*node!=tmpOut.back() && *node!=prevNode)
11098 tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
11099 double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
11104 res=angle0-angleM+2.*M_PI;
11113 if(nextNode!=startNode)
11115 angle0=angleNext-M_PI;
11118 prevNode=tmpOut.back();
11119 tmpOut.push_back(nextNode);
11122 std::vector<int> tmp3(2*(sz-1));
11123 std::vector<int>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
11124 std::copy(nodalConnBg+1,nodalConnEnd,it);
11125 if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
11127 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
11130 if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
11132 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
11137 nodalConnecOut->pushBackSilent((int)INTERP_KERNEL::NORM_POLYGON);
11138 nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
11143 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
11146 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
11150 * This method works on an input pair (\b arr, \b arrIndx) where \b arr indexes is in \b arrIndx.
11151 * 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.
11153 * \param [in] idsToRemoveBg begin of set of ids to remove in \b arr (included)
11154 * \param [in] idsToRemoveEnd end of set of ids to remove in \b arr (excluded)
11155 * \param [in,out] arr array in which the remove operation will be done.
11156 * \param [in,out] arrIndx array in the remove operation will modify
11157 * \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])
11158 * \return true if \b arr and \b arrIndx have been modified, false if not.
11160 bool MEDCouplingUMesh::RemoveIdsFromIndexedArrays(const int *idsToRemoveBg, const int *idsToRemoveEnd, DataArrayInt *arr, DataArrayInt *arrIndx, int offsetForRemoval)
11162 if(!arrIndx || !arr)
11163 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : some input arrays are empty !");
11164 if(offsetForRemoval<0)
11165 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : offsetForRemoval should be >=0 !");
11166 std::set<int> s(idsToRemoveBg,idsToRemoveEnd);
11167 int nbOfGrps=arrIndx->getNumberOfTuples()-1;
11168 int *arrIPtr=arrIndx->getPointer();
11170 int previousArrI=0;
11171 const int *arrPtr=arr->begin();
11172 std::vector<int> arrOut;//no utility to switch to DataArrayInt because copy always needed
11173 for(int i=0;i<nbOfGrps;i++,arrIPtr++)
11175 if(*arrIPtr-previousArrI>offsetForRemoval)
11177 for(const int *work=arrPtr+previousArrI+offsetForRemoval;work!=arrPtr+*arrIPtr;work++)
11179 if(s.find(*work)==s.end())
11180 arrOut.push_back(*work);
11183 previousArrI=*arrIPtr;
11184 *arrIPtr=(int)arrOut.size();
11186 if(arr->getNumberOfTuples()==(int)arrOut.size())
11188 arr->alloc((int)arrOut.size(),1);
11189 std::copy(arrOut.begin(),arrOut.end(),arr->getPointer());
11194 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
11195 * (\ref numbering-indirect).
11196 * This method returns the result of the extraction ( specified by a set of ids in [\b idsOfSelectBg , \b idsOfSelectEnd ) ).
11197 * The selection of extraction is done standardly in new2old format.
11198 * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
11200 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
11201 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
11202 * \param [in] arrIn arr origin array from which the extraction will be done.
11203 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11204 * \param [out] arrOut the resulting array
11205 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11206 * \sa MEDCouplingUMesh::ExtractFromIndexedArraysSlice
11208 void MEDCouplingUMesh::ExtractFromIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11209 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11211 if(!arrIn || !arrIndxIn)
11212 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input pointer is NULL !");
11213 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
11214 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
11215 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input arrays must have exactly one component !");
11216 std::size_t sz=std::distance(idsOfSelectBg,idsOfSelectEnd);
11217 const int *arrInPtr=arrIn->begin();
11218 const int *arrIndxPtr=arrIndxIn->begin();
11219 int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
11221 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
11222 int maxSizeOfArr=arrIn->getNumberOfTuples();
11223 MCAuto<DataArrayInt> arro=DataArrayInt::New();
11224 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11225 arrIo->alloc((int)(sz+1),1);
11226 const int *idsIt=idsOfSelectBg;
11227 int *work=arrIo->getPointer();
11230 for(std::size_t i=0;i<sz;i++,work++,idsIt++)
11232 if(*idsIt>=0 && *idsIt<nbOfGrps)
11233 lgth+=arrIndxPtr[*idsIt+1]-arrIndxPtr[*idsIt];
11236 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " ! Must be in [0," << nbOfGrps << ") !";
11237 throw INTERP_KERNEL::Exception(oss.str());
11243 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " and at this pos arrIndxIn[" << *idsIt;
11244 oss << "+1]-arrIndxIn[" << *idsIt << "] < 0 ! The input index array is bugged !";
11245 throw INTERP_KERNEL::Exception(oss.str());
11248 arro->alloc(lgth,1);
11249 work=arro->getPointer();
11250 idsIt=idsOfSelectBg;
11251 for(std::size_t i=0;i<sz;i++,idsIt++)
11253 if(arrIndxPtr[*idsIt]>=0 && arrIndxPtr[*idsIt+1]<=maxSizeOfArr)
11254 work=std::copy(arrInPtr+arrIndxPtr[*idsIt],arrInPtr+arrIndxPtr[*idsIt+1],work);
11257 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " arrIndx[" << *idsIt << "] must be >= 0 and arrIndx[";
11258 oss << *idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
11259 throw INTERP_KERNEL::Exception(oss.str());
11262 arrOut=arro.retn();
11263 arrIndexOut=arrIo.retn();
11267 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
11268 * (\ref numbering-indirect).
11269 * 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 ).
11270 * The selection of extraction is done standardly in new2old format.
11271 * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
11273 * \param [in] idsOfSelectStart begin of set of ids of the input extraction (included)
11274 * \param [in] idsOfSelectStop end of set of ids of the input extraction (excluded)
11275 * \param [in] idsOfSelectStep
11276 * \param [in] arrIn arr origin array from which the extraction will be done.
11277 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11278 * \param [out] arrOut the resulting array
11279 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11280 * \sa MEDCouplingUMesh::ExtractFromIndexedArrays
11282 void MEDCouplingUMesh::ExtractFromIndexedArraysSlice(int idsOfSelectStart, int idsOfSelectStop, int idsOfSelectStep, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11283 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11285 if(!arrIn || !arrIndxIn)
11286 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input pointer is NULL !");
11287 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
11288 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
11289 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input arrays must have exactly one component !");
11290 int sz=DataArrayInt::GetNumberOfItemGivenBESRelative(idsOfSelectStart,idsOfSelectStop,idsOfSelectStep,"MEDCouplingUMesh::ExtractFromIndexedArraysSlice : Input slice ");
11291 const int *arrInPtr=arrIn->begin();
11292 const int *arrIndxPtr=arrIndxIn->begin();
11293 int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
11295 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
11296 int maxSizeOfArr=arrIn->getNumberOfTuples();
11297 MCAuto<DataArrayInt> arro=DataArrayInt::New();
11298 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11299 arrIo->alloc((int)(sz+1),1);
11300 int idsIt=idsOfSelectStart;
11301 int *work=arrIo->getPointer();
11304 for(int i=0;i<sz;i++,work++,idsIt+=idsOfSelectStep)
11306 if(idsIt>=0 && idsIt<nbOfGrps)
11307 lgth+=arrIndxPtr[idsIt+1]-arrIndxPtr[idsIt];
11310 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " ! Must be in [0," << nbOfGrps << ") !";
11311 throw INTERP_KERNEL::Exception(oss.str());
11317 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " and at this pos arrIndxIn[" << idsIt;
11318 oss << "+1]-arrIndxIn[" << idsIt << "] < 0 ! The input index array is bugged !";
11319 throw INTERP_KERNEL::Exception(oss.str());
11322 arro->alloc(lgth,1);
11323 work=arro->getPointer();
11324 idsIt=idsOfSelectStart;
11325 for(int i=0;i<sz;i++,idsIt+=idsOfSelectStep)
11327 if(arrIndxPtr[idsIt]>=0 && arrIndxPtr[idsIt+1]<=maxSizeOfArr)
11328 work=std::copy(arrInPtr+arrIndxPtr[idsIt],arrInPtr+arrIndxPtr[idsIt+1],work);
11331 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " arrIndx[" << idsIt << "] must be >= 0 and arrIndx[";
11332 oss << idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
11333 throw INTERP_KERNEL::Exception(oss.str());
11336 arrOut=arro.retn();
11337 arrIndexOut=arrIo.retn();
11341 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11342 * 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
11343 * cellIds \b in [ \b idsOfSelectBg , \b idsOfSelectEnd ) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
11344 * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
11346 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
11347 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
11348 * \param [in] arrIn arr origin array from which the extraction will be done.
11349 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11350 * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg, \b idsOfSelectEnd )
11351 * \param [in] srcArrIndex index array of \b srcArr
11352 * \param [out] arrOut the resulting array
11353 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11355 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
11357 void MEDCouplingUMesh::SetPartOfIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11358 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
11359 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11361 if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11362 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArrays : presence of null pointer in input parameter !");
11363 MCAuto<DataArrayInt> arro=DataArrayInt::New();
11364 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11365 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11366 std::vector<bool> v(nbOfTuples,true);
11368 const int *arrIndxInPtr=arrIndxIn->begin();
11369 const int *srcArrIndexPtr=srcArrIndex->begin();
11370 for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
11372 if(*it>=0 && *it<nbOfTuples)
11375 offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[*it+1]-arrIndxInPtr[*it]);
11379 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArrays : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
11380 throw INTERP_KERNEL::Exception(oss.str());
11383 srcArrIndexPtr=srcArrIndex->begin();
11384 arrIo->alloc(nbOfTuples+1,1);
11385 arro->alloc(arrIn->getNumberOfTuples()+offset,1);
11386 const int *arrInPtr=arrIn->begin();
11387 const int *srcArrPtr=srcArr->begin();
11388 int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
11389 int *arroPtr=arro->getPointer();
11390 for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
11394 arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
11395 *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
11399 std::size_t pos=std::distance(idsOfSelectBg,std::find(idsOfSelectBg,idsOfSelectEnd,ii));
11400 arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
11401 *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
11404 arrOut=arro.retn();
11405 arrIndexOut=arrIo.retn();
11409 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11410 * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
11412 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
11413 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
11414 * \param [in,out] arrInOut arr origin array from which the extraction will be done.
11415 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11416 * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg , \b idsOfSelectEnd )
11417 * \param [in] srcArrIndex index array of \b srcArr
11419 * \sa MEDCouplingUMesh::SetPartOfIndexedArrays
11421 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(const int *idsOfSelectBg, const int *idsOfSelectEnd, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
11422 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
11424 if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11425 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : presence of null pointer in input parameter !");
11426 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11427 const int *arrIndxInPtr=arrIndxIn->begin();
11428 const int *srcArrIndexPtr=srcArrIndex->begin();
11429 int *arrInOutPtr=arrInOut->getPointer();
11430 const int *srcArrPtr=srcArr->begin();
11431 for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
11433 if(*it>=0 && *it<nbOfTuples)
11435 if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[*it+1]-arrIndxInPtr[*it])
11436 std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[*it]);
11439 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] !";
11440 throw INTERP_KERNEL::Exception(oss.str());
11445 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
11446 throw INTERP_KERNEL::Exception(oss.str());
11452 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
11453 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
11454 * 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]].
11455 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
11456 * A negative value in \b arrIn means that it is ignored.
11457 * 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.
11459 * \param [in] arrIn arr origin array from which the extraction will be done.
11460 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11461 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
11462 * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
11464 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn)
11466 int seed=0,nbOfDepthPeelingPerformed=0;
11467 return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
11471 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
11472 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
11473 * 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]].
11474 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
11475 * A negative value in \b arrIn means that it is ignored.
11476 * 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.
11477 * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
11478 * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
11479 * \param [in] arrIn arr origin array from which the extraction will be done.
11480 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11481 * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
11482 * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
11483 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
11484 * \sa MEDCouplingUMesh::partitionBySpreadZone
11486 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed)
11488 nbOfDepthPeelingPerformed=0;
11490 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
11491 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11494 DataArrayInt *ret=DataArrayInt::New(); ret->alloc(0,1);
11498 std::vector<bool> fetched(nbOfTuples,false);
11499 return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
11502 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg(std::vector<bool>& fetched, const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed)
11504 nbOfDepthPeelingPerformed=0;
11505 if(!seedBg || !seedEnd || !arrIn || !arrIndxIn)
11506 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg : some input pointer is NULL !");
11507 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11508 std::vector<bool> fetched2(nbOfTuples,false);
11510 for(const int *seedElt=seedBg;seedElt!=seedEnd;seedElt++,i++)
11512 if(*seedElt>=0 && *seedElt<nbOfTuples)
11513 { fetched[*seedElt]=true; fetched2[*seedElt]=true; }
11515 { 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()); }
11517 const int *arrInPtr=arrIn->begin();
11518 const int *arrIndxPtr=arrIndxIn->begin();
11519 int targetNbOfDepthPeeling=nbOfDepthPeeling!=-1?nbOfDepthPeeling:std::numeric_limits<int>::max();
11520 std::vector<int> idsToFetch1(seedBg,seedEnd);
11521 std::vector<int> idsToFetch2;
11522 std::vector<int> *idsToFetch=&idsToFetch1;
11523 std::vector<int> *idsToFetchOther=&idsToFetch2;
11524 while(!idsToFetch->empty() && nbOfDepthPeelingPerformed<targetNbOfDepthPeeling)
11526 for(std::vector<int>::const_iterator it=idsToFetch->begin();it!=idsToFetch->end();it++)
11527 for(const int *it2=arrInPtr+arrIndxPtr[*it];it2!=arrInPtr+arrIndxPtr[*it+1];it2++)
11529 { fetched[*it2]=true; fetched2[*it2]=true; idsToFetchOther->push_back(*it2); }
11530 std::swap(idsToFetch,idsToFetchOther);
11531 idsToFetchOther->clear();
11532 nbOfDepthPeelingPerformed++;
11534 int lgth=(int)std::count(fetched2.begin(),fetched2.end(),true);
11536 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(lgth,1);
11537 int *retPtr=ret->getPointer();
11538 for(std::vector<bool>::const_iterator it=fetched2.begin();it!=fetched2.end();it++,i++)
11545 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11546 * 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
11547 * cellIds \b in [\b idsOfSelectBg, \b idsOfSelectEnd) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
11548 * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
11550 * \param [in] start begin of set of ids of the input extraction (included)
11551 * \param [in] end end of set of ids of the input extraction (excluded)
11552 * \param [in] step step of the set of ids in range mode.
11553 * \param [in] arrIn arr origin array from which the extraction will be done.
11554 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11555 * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
11556 * \param [in] srcArrIndex index array of \b srcArr
11557 * \param [out] arrOut the resulting array
11558 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11560 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx MEDCouplingUMesh::SetPartOfIndexedArrays
11562 void MEDCouplingUMesh::SetPartOfIndexedArraysSlice(int start, int end, int step, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11563 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
11564 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11566 if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11567 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSlice : presence of null pointer in input parameter !");
11568 MCAuto<DataArrayInt> arro=DataArrayInt::New();
11569 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11570 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11572 const int *arrIndxInPtr=arrIndxIn->begin();
11573 const int *srcArrIndexPtr=srcArrIndex->begin();
11574 int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSlice : ");
11576 for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
11578 if(it>=0 && it<nbOfTuples)
11579 offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[it+1]-arrIndxInPtr[it]);
11582 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
11583 throw INTERP_KERNEL::Exception(oss.str());
11586 srcArrIndexPtr=srcArrIndex->begin();
11587 arrIo->alloc(nbOfTuples+1,1);
11588 arro->alloc(arrIn->getNumberOfTuples()+offset,1);
11589 const int *arrInPtr=arrIn->begin();
11590 const int *srcArrPtr=srcArr->begin();
11591 int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
11592 int *arroPtr=arro->getPointer();
11593 for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
11595 int pos=DataArray::GetPosOfItemGivenBESRelativeNoThrow(ii,start,end,step);
11598 arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
11599 *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
11603 arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
11604 *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
11607 arrOut=arro.retn();
11608 arrIndexOut=arrIo.retn();
11612 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11613 * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
11615 * \param [in] start begin of set of ids of the input extraction (included)
11616 * \param [in] end end of set of ids of the input extraction (excluded)
11617 * \param [in] step step of the set of ids in range mode.
11618 * \param [in,out] arrInOut arr origin array from which the extraction will be done.
11619 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11620 * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
11621 * \param [in] srcArrIndex index array of \b srcArr
11623 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSlice MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
11625 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(int start, int end, int step, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
11626 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
11628 if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11629 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : presence of null pointer in input parameter !");
11630 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11631 const int *arrIndxInPtr=arrIndxIn->begin();
11632 const int *srcArrIndexPtr=srcArrIndex->begin();
11633 int *arrInOutPtr=arrInOut->getPointer();
11634 const int *srcArrPtr=srcArr->begin();
11635 int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : ");
11637 for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
11639 if(it>=0 && it<nbOfTuples)
11641 if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[it+1]-arrIndxInPtr[it])
11642 std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[it]);
11645 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " id (idsOfSelectBg[" << i << "]) is " << it << " arrIndxIn[id+1]-arrIndxIn[id]!=srcArrIndex[pos+1]-srcArrIndex[pos] !";
11646 throw INTERP_KERNEL::Exception(oss.str());
11651 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
11652 throw INTERP_KERNEL::Exception(oss.str());
11658 * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
11659 * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
11660 * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
11661 * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
11662 * The sum of measure field of returned mesh is equal to the sum of measure field of this.
11664 * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
11666 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
11668 checkFullyDefined();
11669 int mdim=getMeshDimension();
11670 int spaceDim=getSpaceDimension();
11672 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
11673 std::vector<DataArrayInt *> partition=partitionBySpreadZone();
11674 std::vector< MCAuto<DataArrayInt> > partitionAuto; partitionAuto.reserve(partition.size());
11675 std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayInt> > >(partitionAuto));
11676 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
11677 ret->setCoords(getCoords());
11678 ret->allocateCells((int)partition.size());
11680 for(std::vector<DataArrayInt *>::const_iterator it=partition.begin();it!=partition.end();it++)
11682 MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
11683 MCAuto<DataArrayInt> cell;
11687 cell=tmp->buildUnionOf2DMesh();
11690 cell=tmp->buildUnionOf3DMesh();
11693 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
11696 ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->begin()+1);
11699 ret->finishInsertingCells();
11704 * This method partitions \b this into contiguous zone.
11705 * This method only needs a well defined connectivity. Coordinates are not considered here.
11706 * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
11708 std::vector<DataArrayInt *> MEDCouplingUMesh::partitionBySpreadZone() const
11710 DataArrayInt *neigh=0,*neighI=0;
11711 computeNeighborsOfCells(neigh,neighI);
11712 MCAuto<DataArrayInt> neighAuto(neigh),neighIAuto(neighI);
11713 return PartitionBySpreadZone(neighAuto,neighIAuto);
11716 std::vector<DataArrayInt *> MEDCouplingUMesh::PartitionBySpreadZone(const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn)
11718 if(!arrIn || !arrIndxIn)
11719 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : null input pointers !");
11720 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
11721 int nbOfTuples(arrIndxIn->getNumberOfTuples());
11722 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1 || nbOfTuples<1)
11723 throw INTERP_KERNEL::Exception("PartitionBySpreadZone : invalid arrays in input !");
11724 int nbOfCellsCur(nbOfTuples-1);
11725 std::vector<DataArrayInt *> ret;
11726 if(nbOfCellsCur<=0)
11728 std::vector<bool> fetchedCells(nbOfCellsCur,false);
11729 std::vector< MCAuto<DataArrayInt> > ret2;
11731 while(seed<nbOfCellsCur)
11733 int nbOfPeelPerformed=0;
11734 ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfPeelPerformed));
11735 seed=(int)std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false));
11737 for(std::vector< MCAuto<DataArrayInt> >::iterator it=ret2.begin();it!=ret2.end();it++)
11738 ret.push_back((*it).retn());
11743 * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
11744 * newly allocated DataArrayInt instance with 2 components ready to be interpreted as input of DataArrayInt::findRangeIdForEachTuple method.
11746 * \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.
11747 * \return a newly allocated DataArrayInt to be managed by the caller.
11748 * \throw In case of \a code has not the right format (typically of size 3*n)
11750 DataArrayInt *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<int>& code)
11752 MCAuto<DataArrayInt> ret=DataArrayInt::New();
11753 std::size_t nb=code.size()/3;
11754 if(code.size()%3!=0)
11755 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
11756 ret->alloc((int)nb,2);
11757 int *retPtr=ret->getPointer();
11758 for(std::size_t i=0;i<nb;i++,retPtr+=2)
11760 retPtr[0]=code[3*i+2];
11761 retPtr[1]=code[3*i+2]+code[3*i+1];
11767 * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
11768 * All cells in \a this are expected to be linear 3D cells.
11769 * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
11770 * It leads to an increase to number of cells.
11771 * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
11772 * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
11773 * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
11775 * \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.
11776 * For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
11777 * \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.
11778 * \param [out] n2oCells - A new instance of DataArrayInt holding, for each new cell,
11779 * an id of old cell producing it. The caller is to delete this array using
11780 * decrRef() as it is no more needed.
11781 * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
11783 * \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
11784 * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
11786 * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
11787 * \throw If \a this is not fully constituted with linear 3D cells.
11788 * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
11790 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayInt *& n2oCells, int& nbOfAdditionalPoints) const
11792 INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
11793 checkConnectivityFullyDefined();
11794 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
11795 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
11796 int nbOfCells(getNumberOfCells()),nbNodes(getNumberOfNodes());
11797 MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
11798 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfCells,1);
11799 int *retPt(ret->getPointer());
11800 MCAuto<DataArrayInt> newConn(DataArrayInt::New()); newConn->alloc(0,1);
11801 MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
11802 const int *oldc(_nodal_connec->begin());
11803 const int *oldci(_nodal_connec_index->begin());
11804 const double *coords(_coords->begin());
11805 for(int i=0;i<nbOfCells;i++,oldci++,retPt++)
11807 std::vector<int> a; std::vector<double> b;
11808 INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
11809 std::size_t nbOfTet(a.size()/4); *retPt=(int)nbOfTet;
11810 const int *aa(&a[0]);
11813 for(std::vector<int>::iterator it=a.begin();it!=a.end();it++)
11815 *it=(-(*(it))-1+nbNodes);
11816 addPts->insertAtTheEnd(b.begin(),b.end());
11817 nbNodes+=(int)b.size()/3;
11819 for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
11820 newConn->insertAtTheEnd(aa,aa+4);
11822 if(!addPts->empty())
11824 addPts->rearrange(3);
11825 nbOfAdditionalPoints=addPts->getNumberOfTuples();
11826 addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
11827 ret0->setCoords(addPts);
11831 nbOfAdditionalPoints=0;
11832 ret0->setCoords(getCoords());
11834 ret0->setNodalConnectivity(newConn);
11836 ret->computeOffsetsFull();
11837 n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
11838 return ret0.retn();
11842 * 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).
11844 * \sa MEDCouplingUMesh::split2DCells
11846 void MEDCouplingUMesh::split2DCellsLinear(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI)
11848 checkConnectivityFullyDefined();
11849 int ncells(getNumberOfCells()),lgthToReach(getNodalConnectivityArrayLen()+subNodesInSeg->getNumberOfTuples());
11850 MCAuto<DataArrayInt> c(DataArrayInt::New()); c->alloc((std::size_t)lgthToReach);
11851 const int *subPtr(subNodesInSeg->begin()),*subIPtr(subNodesInSegI->begin()),*descPtr(desc->begin()),*descIPtr(descI->begin()),*oldConn(getNodalConnectivity()->begin());
11852 int *cPtr(c->getPointer()),*ciPtr(getNodalConnectivityIndex()->getPointer());
11853 int prevPosOfCi(ciPtr[0]);
11854 for(int i=0;i<ncells;i++,ciPtr++,descIPtr++)
11856 int offset(descIPtr[0]),sz(descIPtr[1]-descIPtr[0]),deltaSz(0);
11857 *cPtr++=(int)INTERP_KERNEL::NORM_POLYGON; *cPtr++=oldConn[prevPosOfCi+1];
11858 for(int j=0;j<sz;j++)
11860 int offset2(subIPtr[descPtr[offset+j]]),sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]);
11861 for(int k=0;k<sz2;k++)
11862 *cPtr++=subPtr[offset2+k];
11864 *cPtr++=oldConn[prevPosOfCi+j+2];
11867 prevPosOfCi=ciPtr[1];
11868 ciPtr[1]=ciPtr[0]+1+sz+deltaSz;//sz==old nb of nodes because (nb of subedges=nb of nodes for polygons)
11871 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCellsLinear : Some of edges to be split are orphan !");
11872 _nodal_connec->decrRef();
11873 _nodal_connec=c.retn(); _types.clear(); _types.insert(INTERP_KERNEL::NORM_POLYGON);
11876 int InternalAddPoint(const INTERP_KERNEL::Edge *e, int id, const double *coo, int startId, int endId, DataArrayDouble& addCoo, int& nodesCnter)
11882 int ret(nodesCnter++);
11884 e->getMiddleOfPoints(coo+2*startId,coo+2*endId,newPt);
11885 addCoo.insertAtTheEnd(newPt,newPt+2);
11890 int InternalAddPointOriented(const INTERP_KERNEL::Edge *e, int id, const double *coo, int startId, int endId, DataArrayDouble& addCoo, int& nodesCnter)
11896 int ret(nodesCnter++);
11898 e->getMiddleOfPointsOriented(coo+2*startId,coo+2*endId,newPt);
11899 addCoo.insertAtTheEnd(newPt,newPt+2);
11907 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)
11910 int trueStart(start>=0?start:nbOfEdges+start);
11911 tmp[0]=linOrArc?(int)INTERP_KERNEL::NORM_QPOLYG:(int)INTERP_KERNEL::NORM_POLYGON; tmp[1]=connBg[trueStart]; tmp[2]=connBg[stp];
11912 newConnOfCell->insertAtTheEnd(tmp,tmp+3);
11917 int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11918 InternalAddPointOriented(e,-1,coords,tmp[1],tmp[2],*appendedCoords,tmp2);
11919 middles.push_back(tmp3+offset);
11922 middles.push_back(connBg[trueStart+nbOfEdges]);
11926 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)
11928 int tmpSrt(newConnOfCell->back()),tmpEnd(connBg[stp]);
11929 newConnOfCell->pushBackSilent(tmpEnd);
11934 int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11935 InternalAddPointOriented(e,-1,coords,tmpSrt,tmpEnd,*appendedCoords,tmp2);
11936 middles.push_back(tmp3+offset);
11939 middles.push_back(connBg[start+nbOfEdges]);
11943 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)
11945 // only the quadratic point to deal with:
11950 int tmpSrt(connBg[start]),tmpEnd(connBg[stp]);
11951 int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11952 InternalAddPointOriented(e,-1,coords,tmpSrt,tmpEnd,*appendedCoords,tmp2);
11953 middles.push_back(tmp3+offset);
11956 middles.push_back(connBg[start+nbOfEdges]);
11963 * 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 ) .
11964 * \a appendedCoords is a DataArrayDouble instance with number of components equal to one (even if the items are pushed by pair).
11966 bool MEDCouplingUMesh::Colinearize2DCell(const double *coords, const int *connBg, const int *connEnd, int offset, DataArrayInt *newConnOfCell, DataArrayDouble *appendedCoords)
11968 std::size_t sz(std::distance(connBg,connEnd));
11969 if(sz<3)//3 because 2+1(for the cell type) and 2 is the minimal number of edges of 2D cell.
11970 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Colinearize2DCell : the input cell has invalid format !");
11972 INTERP_KERNEL::AutoPtr<int> tmpConn(new int[sz]);
11973 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connBg[0]));
11974 unsigned nbs(cm.getNumberOfSons2(connBg+1,sz));
11975 unsigned nbOfHit(0); // number of fusions operated
11976 int posBaseElt(0),posEndElt(0),nbOfTurn(0);
11977 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
11978 INTERP_KERNEL::NormalizedCellType typeOfSon;
11979 std::vector<int> middles;
11981 for(;(nbOfTurn+nbOfHit)<nbs;nbOfTurn++)
11983 cm.fillSonCellNodalConnectivity2(posBaseElt,connBg+1,sz,tmpConn,typeOfSon);
11984 std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
11985 INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11986 posEndElt = posBaseElt+1;
11988 // Look backward first: are the final edges of the cells colinear with the first ones?
11989 // This initializes posBaseElt.
11992 for(unsigned i=1;i<nbs && nbOfHit<maxNbOfHit;i++) // 2nd condition is to avoid ending with a cell wih one single edge
11994 cm.fillSonCellNodalConnectivity2(nbs-i,connBg+1,sz,tmpConn,typeOfSon);
11995 INTERP_KERNEL::Edge *eCand(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11996 INTERP_KERNEL::EdgeIntersector *eint(INTERP_KERNEL::Edge::BuildIntersectorWith(e,eCand));
11997 bool isColinear=eint->areColinears();
12010 // Now move forward:
12011 const unsigned fwdStart = (nbOfTurn == 0 ? 0 : posBaseElt); // the first element to be inspected going forward
12012 for(unsigned j=fwdStart+1;j<nbs && nbOfHit<maxNbOfHit;j++) // 2nd condition is to avoid ending with a cell wih one single edge
12014 cm.fillSonCellNodalConnectivity2((int)j,connBg+1,sz,tmpConn,typeOfSon); // get edge #j's connectivity
12015 INTERP_KERNEL::Edge *eCand(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
12016 INTERP_KERNEL::EdgeIntersector *eint(INTERP_KERNEL::Edge::BuildIntersectorWith(e,eCand));
12017 bool isColinear(eint->areColinears());
12029 //push [posBaseElt,posEndElt) in newConnOfCell using e
12030 // 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!
12032 // at the begining of the connectivity (insert type)
12033 EnterTheResultOf2DCellFirst(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
12034 else if((nbOfHit+nbOfTurn) != (nbs-1))
12036 EnterTheResultOf2DCellMiddle(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
12037 if ((nbOfHit+nbOfTurn) == (nbs-1))
12038 // at the end (only quad points to deal with)
12039 EnterTheResultOf2DCellEnd(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
12040 posBaseElt=posEndElt;
12043 if(!middles.empty())
12044 newConnOfCell->insertAtTheEnd(middles.begin(),middles.end());
12049 * It is the quadratic part of MEDCouplingUMesh::split2DCells. Here some additionnal nodes can be added at the end of coordinates array object.
12051 * \return int - the number of new nodes created.
12052 * \sa MEDCouplingUMesh::split2DCells
12054 int MEDCouplingUMesh::split2DCellsQuadratic(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *mid, const DataArrayInt *midI)
12056 checkConsistencyLight();
12057 int ncells(getNumberOfCells()),lgthToReach(getNodalConnectivityArrayLen()+2*subNodesInSeg->getNumberOfTuples()),nodesCnt(getNumberOfNodes());
12058 MCAuto<DataArrayInt> c(DataArrayInt::New()); c->alloc((std::size_t)lgthToReach);
12059 MCAuto<DataArrayDouble> addCoo(DataArrayDouble::New()); addCoo->alloc(0,1);
12060 const int *subPtr(subNodesInSeg->begin()),*subIPtr(subNodesInSegI->begin()),*descPtr(desc->begin()),*descIPtr(descI->begin()),*oldConn(getNodalConnectivity()->begin());
12061 const int *midPtr(mid->begin()),*midIPtr(midI->begin());
12062 const double *oldCoordsPtr(getCoords()->begin());
12063 int *cPtr(c->getPointer()),*ciPtr(getNodalConnectivityIndex()->getPointer());
12064 int prevPosOfCi(ciPtr[0]);
12065 for(int i=0;i<ncells;i++,ciPtr++,descIPtr++)
12067 int offset(descIPtr[0]),sz(descIPtr[1]-descIPtr[0]),deltaSz(sz);
12068 for(int j=0;j<sz;j++)
12069 { int sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]); deltaSz+=sz2; }
12070 *cPtr++=(int)INTERP_KERNEL::NORM_QPOLYG; cPtr[0]=oldConn[prevPosOfCi+1];
12071 for(int j=0;j<sz;j++)//loop over subedges of oldConn
12073 int offset2(subIPtr[descPtr[offset+j]]),sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]),offset3(midIPtr[descPtr[offset+j]]);
12077 cPtr[1]=oldConn[prevPosOfCi+2+j];
12078 cPtr[deltaSz]=oldConn[prevPosOfCi+1+j+sz]; cPtr++;
12081 std::vector<INTERP_KERNEL::Node *> ns(3);
12082 ns[0]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+j]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+j]+1]);
12083 ns[1]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+(1+j)%sz]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+(1+j)%sz]+1]);
12084 ns[2]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+sz+j]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+sz+j]+1]);
12085 MCAuto<INTERP_KERNEL::Edge> e(INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(ns));
12086 for(int k=0;k<sz2;k++)//loop over subsplit of current subedge
12088 cPtr[1]=subPtr[offset2+k];
12089 cPtr[deltaSz]=InternalAddPoint(e,midPtr[offset3+k],oldCoordsPtr,cPtr[0],cPtr[1],*addCoo,nodesCnt); cPtr++;
12091 int tmpEnd(oldConn[prevPosOfCi+1+(j+1)%sz]);
12093 { cPtr[1]=tmpEnd; }
12094 cPtr[deltaSz]=InternalAddPoint(e,midPtr[offset3+sz2],oldCoordsPtr,cPtr[0],tmpEnd,*addCoo,nodesCnt); cPtr++;
12096 prevPosOfCi=ciPtr[1]; cPtr+=deltaSz;
12097 ciPtr[1]=ciPtr[0]+1+2*deltaSz;//sz==old nb of nodes because (nb of subedges=nb of nodes for polygons)
12100 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCellsQuadratic : Some of edges to be split are orphan !");
12101 _nodal_connec->decrRef();
12102 _nodal_connec=c.retn(); _types.clear(); _types.insert(INTERP_KERNEL::NORM_QPOLYG);
12103 addCoo->rearrange(2);
12104 MCAuto<DataArrayDouble> coo(DataArrayDouble::Aggregate(getCoords(),addCoo));//info are copied from getCoords() by using Aggregate
12106 return addCoo->getNumberOfTuples();
12109 void MEDCouplingUMesh::ComputeAllTypesInternal(std::set<INTERP_KERNEL::NormalizedCellType>& types, const DataArrayInt *nodalConnec, const DataArrayInt *nodalConnecIndex)
12111 if(nodalConnec && nodalConnecIndex)
12114 const int *conn(nodalConnec->begin()),*connIndex(nodalConnecIndex->begin());
12115 int nbOfElem(nodalConnecIndex->getNbOfElems()-1);
12117 for(const int *pt=connIndex;pt!=connIndex+nbOfElem;pt++)
12118 types.insert((INTERP_KERNEL::NormalizedCellType)conn[*pt]);
12122 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
12123 _own_cell(true),_cell_id(-1),_nb_cell(0)
12128 _nb_cell=mesh->getNumberOfCells();
12132 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
12140 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_cell(itc),
12141 _own_cell(false),_cell_id(bg-1),
12148 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
12151 if(_cell_id<_nb_cell)
12160 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
12166 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
12168 return new MEDCouplingUMeshCellByTypeIterator(_mesh);
12171 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
12177 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh, INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_type(type),
12185 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
12191 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
12196 int MEDCouplingUMeshCellEntry::getNumberOfElems() const
12201 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
12203 return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
12206 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
12211 _nb_cell=mesh->getNumberOfCells();
12215 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
12222 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
12224 const int *c=_mesh->getNodalConnectivity()->begin();
12225 const int *ci=_mesh->getNodalConnectivityIndex()->begin();
12226 if(_cell_id<_nb_cell)
12228 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
12229 int nbOfElems=(int)std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type)));
12230 int startId=_cell_id;
12231 _cell_id+=nbOfElems;
12232 return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
12238 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
12242 _conn=mesh->getNodalConnectivity()->getPointer();
12243 _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
12247 void MEDCouplingUMeshCell::next()
12249 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
12254 _conn_lgth=_conn_indx[1]-_conn_indx[0];
12257 std::string MEDCouplingUMeshCell::repr() const
12259 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
12261 std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
12263 std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<int>(oss," "));
12267 return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
12270 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
12272 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
12273 return (INTERP_KERNEL::NormalizedCellType)_conn[0];
12275 return INTERP_KERNEL::NORM_ERROR;
12278 const int *MEDCouplingUMeshCell::getAllConn(int& lgth) const
12281 if(_conn_lgth!=NOTICABLE_FIRST_VAL)