1 // Copyright (C) 2007-2016 CEA/DEN, EDF R&D
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 // Author : Anthony Geay (CEA/DEN)
21 #include "MEDCouplingUMesh.hxx"
22 #include "MEDCoupling1GTUMesh.hxx"
23 #include "MEDCouplingMemArray.txx"
24 #include "MEDCouplingFieldDouble.hxx"
25 #include "MEDCouplingSkyLineArray.hxx"
26 #include "CellModel.hxx"
27 #include "VolSurfUser.txx"
28 #include "InterpolationUtils.hxx"
29 #include "PointLocatorAlgos.txx"
31 #include "BBTreeDst.txx"
32 #include "SplitterTetra.hxx"
33 #include "DiameterCalculator.hxx"
34 #include "DirectedBoundingBox.hxx"
35 #include "InterpKernelMatrixTools.hxx"
36 #include "InterpKernelMeshQuality.hxx"
37 #include "InterpKernelCellSimplify.hxx"
38 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
39 #include "InterpKernelAutoPtr.hxx"
40 #include "InterpKernelGeo2DNode.hxx"
41 #include "InterpKernelGeo2DEdgeLin.hxx"
42 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
43 #include "InterpKernelGeo2DQuadraticPolygon.hxx"
52 using namespace MEDCoupling;
54 double MEDCouplingUMesh::EPS_FOR_POLYH_ORIENTATION=1.e-14;
57 const INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::MEDMEM_ORDER[N_MEDMEM_ORDER] = { INTERP_KERNEL::NORM_POINT1, INTERP_KERNEL::NORM_SEG2, INTERP_KERNEL::NORM_SEG3, INTERP_KERNEL::NORM_SEG4, INTERP_KERNEL::NORM_POLYL, INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4, INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_TRI7, INTERP_KERNEL::NORM_QUAD8, INTERP_KERNEL::NORM_QUAD9, INTERP_KERNEL::NORM_POLYGON, INTERP_KERNEL::NORM_QPOLYG, INTERP_KERNEL::NORM_TETRA4, INTERP_KERNEL::NORM_PYRA5, INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXA8, INTERP_KERNEL::NORM_HEXGP12, INTERP_KERNEL::NORM_TETRA10, INTERP_KERNEL::NORM_PYRA13, INTERP_KERNEL::NORM_PENTA15, INTERP_KERNEL::NORM_HEXA20, INTERP_KERNEL::NORM_HEXA27, INTERP_KERNEL::NORM_POLYHED };
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);
869 * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm
870 * of MEDCouplingUMesh::computeNeighborsOfCells.
871 * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is
872 * typically the case to extract a set a neighbours,
873 * excluding a set of meshdim-1 cells in input descending connectivity.
874 * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx (\ref numbering-indirect) input params are
875 * the result of MEDCouplingUMesh::buildDescendingConnectivity.
876 * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities
878 * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
880 * \param [in] desc descending connectivity array.
881 * \param [in] descIndx descending connectivity index array used to walk through \b desc (\ref numbering-indirect).
882 * \param [in] revDesc reverse descending connectivity array.
883 * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc (\ref numbering-indirect).
884 * \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
885 * parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
886 * \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.
888 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayInt *desc, const DataArrayInt *descIndx, const DataArrayInt *revDesc, const DataArrayInt *revDescIndx,
889 DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx)
891 if(!desc || !descIndx || !revDesc || !revDescIndx)
892 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
893 const int *descPtr=desc->getConstPointer();
894 const int *descIPtr=descIndx->getConstPointer();
895 const int *revDescPtr=revDesc->getConstPointer();
896 const int *revDescIPtr=revDescIndx->getConstPointer();
898 int nbCells=descIndx->getNumberOfTuples()-1;
899 MCAuto<DataArrayInt> out0=DataArrayInt::New();
900 MCAuto<DataArrayInt> out1=DataArrayInt::New(); out1->alloc(nbCells+1,1);
901 int *out1Ptr=out1->getPointer();
903 out0->reserve(desc->getNumberOfTuples());
904 for(int i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
906 for(const int *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
908 std::set<int> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
910 out0->insertAtTheEnd(s.begin(),s.end());
912 *out1Ptr=out0->getNumberOfTuples();
914 neighbors=out0.retn();
915 neighborsIndx=out1.retn();
919 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
920 * For speed reasons no check of this will be done. This method calls
921 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
922 * This method lists node by node in \b this which are its neighbors. To compute the result
923 * only connectivities are considered.
924 * The neighbor nodes of node having id 'nodeId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
926 * \param [out] neighbors is an array storing all the neighbors of all nodes in \b this. This array
927 * is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
928 * parameter allows to select the right part in this array (\ref numbering-indirect).
929 * The number of tuples is equal to the last values in \b neighborsIndx.
930 * \param [out] neighborsIdx is an array of size this->getNumberOfCells()+1 newly allocated and should
931 * be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
933 void MEDCouplingUMesh::computeNeighborsOfNodes(DataArrayInt *&neighbors, DataArrayInt *&neighborsIdx) const
936 int mdim(getMeshDimension()),nbNodes(getNumberOfNodes());
937 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descIndx(DataArrayInt::New()),revDesc(DataArrayInt::New()),revDescIndx(DataArrayInt::New());
938 MCAuto<MEDCouplingUMesh> mesh1D;
943 mesh1D=explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx);
948 mesh1D=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
953 mesh1D=const_cast<MEDCouplingUMesh *>(this);
959 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2,1] !");
962 desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=0; revDescIndx=0;
963 mesh1D->getReverseNodalConnectivity(desc,descIndx);
964 MCAuto<DataArrayInt> ret0(DataArrayInt::New());
965 ret0->alloc(desc->getNumberOfTuples(),1);
966 int *r0Pt(ret0->getPointer());
967 const int *c1DPtr(mesh1D->getNodalConnectivity()->begin()),*rn(desc->begin()),*rni(descIndx->begin());
968 for(int i=0;i<nbNodes;i++,rni++)
970 for(const int *oneDCellIt=rn+rni[0];oneDCellIt!=rn+rni[1];oneDCellIt++)
971 *r0Pt++=c1DPtr[3*(*oneDCellIt)+1]==i?c1DPtr[3*(*oneDCellIt)+2]:c1DPtr[3*(*oneDCellIt)+1];
973 neighbors=ret0.retn();
974 neighborsIdx=descIndx.retn();
980 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
981 * For speed reasons no check of this will be done.
983 template<class SonsGenerator>
984 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivityGen(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx, DimM1DescNbrer nbrer) const
986 if(!desc || !descIndx || !revDesc || !revDescIndx)
987 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildDescendingConnectivityGen : present of a null pointer in input !");
988 checkConnectivityFullyDefined();
989 int nbOfCells=getNumberOfCells();
990 int nbOfNodes=getNumberOfNodes();
991 MCAuto<DataArrayInt> revNodalIndx=DataArrayInt::New(); revNodalIndx->alloc(nbOfNodes+1,1); revNodalIndx->fillWithZero();
992 int *revNodalIndxPtr=revNodalIndx->getPointer();
993 const int *conn=_nodal_connec->getConstPointer();
994 const int *connIndex=_nodal_connec_index->getConstPointer();
995 std::string name="Mesh constituent of "; name+=getName();
996 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(name,getMeshDimension()-SonsGenerator::DELTA);
997 ret->setCoords(getCoords());
998 ret->allocateCells(2*nbOfCells);
999 descIndx->alloc(nbOfCells+1,1);
1000 MCAuto<DataArrayInt> revDesc2(DataArrayInt::New()); revDesc2->reserve(2*nbOfCells);
1001 int *descIndxPtr=descIndx->getPointer(); *descIndxPtr++=0;
1002 for(int eltId=0;eltId<nbOfCells;eltId++,descIndxPtr++)
1004 int pos=connIndex[eltId];
1005 int posP1=connIndex[eltId+1];
1006 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[pos]);
1007 SonsGenerator sg(cm);
1008 unsigned nbOfSons=sg.getNumberOfSons2(conn+pos+1,posP1-pos-1);
1009 INTERP_KERNEL::AutoPtr<int> tmp=new int[posP1-pos];
1010 for(unsigned i=0;i<nbOfSons;i++)
1012 INTERP_KERNEL::NormalizedCellType cmsId;
1013 unsigned nbOfNodesSon=sg.fillSonCellNodalConnectivity2(i,conn+pos+1,posP1-pos-1,tmp,cmsId);
1014 for(unsigned k=0;k<nbOfNodesSon;k++)
1016 revNodalIndxPtr[tmp[k]+1]++;
1017 ret->insertNextCell(cmsId,nbOfNodesSon,tmp);
1018 revDesc2->pushBackSilent(eltId);
1020 descIndxPtr[0]=descIndxPtr[-1]+(int)nbOfSons;
1022 int nbOfCellsM1=ret->getNumberOfCells();
1023 std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<int>());
1024 MCAuto<DataArrayInt> revNodal=DataArrayInt::New(); revNodal->alloc(revNodalIndx->back(),1);
1025 std::fill(revNodal->getPointer(),revNodal->getPointer()+revNodalIndx->back(),-1);
1026 int *revNodalPtr=revNodal->getPointer();
1027 const int *connM1=ret->getNodalConnectivity()->getConstPointer();
1028 const int *connIndexM1=ret->getNodalConnectivityIndex()->getConstPointer();
1029 for(int eltId=0;eltId<nbOfCellsM1;eltId++)
1031 const int *strtNdlConnOfCurCell=connM1+connIndexM1[eltId]+1;
1032 const int *endNdlConnOfCurCell=connM1+connIndexM1[eltId+1];
1033 for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
1034 if(*iter>=0)//for polyhedrons
1035 *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind2nd(std::equal_to<int>(),-1))=eltId;
1038 DataArrayInt *commonCells=0,*commonCellsI=0;
1039 FindCommonCellsAlg(3,0,ret->getNodalConnectivity(),ret->getNodalConnectivityIndex(),revNodal,revNodalIndx,commonCells,commonCellsI);
1040 MCAuto<DataArrayInt> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1041 const int *commonCellsPtr(commonCells->getConstPointer()),*commonCellsIPtr(commonCellsI->getConstPointer());
1042 int newNbOfCellsM1=-1;
1043 MCAuto<DataArrayInt> o2nM1=DataArrayInt::ConvertIndexArrayToO2N(nbOfCellsM1,commonCells->begin(),
1044 commonCellsI->begin(),commonCellsI->end(),newNbOfCellsM1);
1045 std::vector<bool> isImpacted(nbOfCellsM1,false);
1046 for(const int *work=commonCellsI->begin();work!=commonCellsI->end()-1;work++)
1047 for(int work2=work[0];work2!=work[1];work2++)
1048 isImpacted[commonCellsPtr[work2]]=true;
1049 const int *o2nM1Ptr=o2nM1->getConstPointer();
1050 MCAuto<DataArrayInt> n2oM1=o2nM1->invertArrayO2N2N2OBis(newNbOfCellsM1);
1051 const int *n2oM1Ptr=n2oM1->getConstPointer();
1052 MCAuto<MEDCouplingUMesh> ret2=static_cast<MEDCouplingUMesh *>(ret->buildPartOfMySelf(n2oM1->begin(),n2oM1->end(),true));
1053 ret2->copyTinyInfoFrom(this);
1054 desc->alloc(descIndx->back(),1);
1055 int *descPtr=desc->getPointer();
1056 const INTERP_KERNEL::CellModel& cmsDft=INTERP_KERNEL::CellModel::GetCellModel(INTERP_KERNEL::NORM_POINT1);
1057 for(int i=0;i<nbOfCellsM1;i++,descPtr++)
1060 *descPtr=nbrer(o2nM1Ptr[i],0,cmsDft,false,0,0);
1063 if(i!=n2oM1Ptr[o2nM1Ptr[i]])
1065 const INTERP_KERNEL::CellModel& cms=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connM1[connIndexM1[i]]);
1066 *descPtr=nbrer(o2nM1Ptr[i],connIndexM1[i+1]-connIndexM1[i]-1,cms,true,connM1+connIndexM1[n2oM1Ptr[o2nM1Ptr[i]]]+1,connM1+connIndexM1[i]+1);
1069 *descPtr=nbrer(o2nM1Ptr[i],0,cmsDft,false,0,0);
1072 revDesc->reserve(newNbOfCellsM1);
1073 revDescIndx->alloc(newNbOfCellsM1+1,1);
1074 int *revDescIndxPtr=revDescIndx->getPointer(); *revDescIndxPtr++=0;
1075 const int *revDesc2Ptr=revDesc2->getConstPointer();
1076 for(int i=0;i<newNbOfCellsM1;i++,revDescIndxPtr++)
1078 int oldCellIdM1=n2oM1Ptr[i];
1079 if(!isImpacted[oldCellIdM1])
1081 revDesc->pushBackSilent(revDesc2Ptr[oldCellIdM1]);
1082 revDescIndxPtr[0]=revDescIndxPtr[-1]+1;
1086 for(int j=commonCellsIPtr[0];j<commonCellsIPtr[1];j++)
1087 revDesc->pushBackSilent(revDesc2Ptr[commonCellsPtr[j]]);
1088 revDescIndxPtr[0]=revDescIndxPtr[-1]+commonCellsIPtr[1]-commonCellsIPtr[0];
1096 struct MEDCouplingAccVisit
1098 MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1099 int operator()(int val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1100 int _new_nb_of_nodes;
1106 * Converts specified cells to either polygons (if \a this is a 2D mesh) or
1107 * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an
1108 * array of cell ids. Pay attention that after conversion all algorithms work slower
1109 * with \a this mesh than before conversion. <br> If an exception is thrown during the
1110 * conversion due presence of invalid ids in the array of cells to convert, as a
1111 * result \a this mesh contains some already converted elements. In this case the 2D
1112 * mesh remains valid but 3D mesh becomes \b inconsistent!
1113 * \warning This method can significantly modify the order of geometric types in \a this,
1114 * hence, to write this mesh to the MED file, its cells must be sorted using
1115 * sortCellsInMEDFileFrmt().
1116 * \param [in] cellIdsToConvertBg - the array holding ids of cells to convert.
1117 * \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a
1118 * cellIdsToConvertBg.
1119 * \throw If the coordinates array is not set.
1120 * \throw If the nodal connectivity of cells is node defined.
1121 * \throw If dimension of \a this mesh is not either 2 or 3.
1123 * \if ENABLE_EXAMPLES
1124 * \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".<br>
1125 * \ref py_mcumesh_convertToPolyTypes "Here is a Python example".
1128 void MEDCouplingUMesh::convertToPolyTypes(const int *cellIdsToConvertBg, const int *cellIdsToConvertEnd)
1130 checkFullyDefined();
1131 int dim=getMeshDimension();
1133 throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
1134 int nbOfCells(getNumberOfCells());
1137 const int *connIndex=_nodal_connec_index->getConstPointer();
1138 int *conn=_nodal_connec->getPointer();
1139 for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1141 if(*iter>=0 && *iter<nbOfCells)
1143 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
1144 if(!cm.isQuadratic())
1145 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
1147 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
1151 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1152 oss << " in range [0," << nbOfCells << ") !";
1153 throw INTERP_KERNEL::Exception(oss.str());
1159 int *connIndex(_nodal_connec_index->getPointer());
1160 const int *connOld(_nodal_connec->getConstPointer());
1161 MCAuto<DataArrayInt> connNew(DataArrayInt::New()),connNewI(DataArrayInt::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0);
1162 std::vector<bool> toBeDone(nbOfCells,false);
1163 for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1165 if(*iter>=0 && *iter<nbOfCells)
1166 toBeDone[*iter]=true;
1169 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1170 oss << " in range [0," << nbOfCells << ") !";
1171 throw INTERP_KERNEL::Exception(oss.str());
1174 for(int cellId=0;cellId<nbOfCells;cellId++)
1176 int pos(connIndex[cellId]),posP1(connIndex[cellId+1]);
1177 int lgthOld(posP1-pos-1);
1178 if(toBeDone[cellId])
1180 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connOld[pos]);
1181 unsigned nbOfFaces(cm.getNumberOfSons2(connOld+pos+1,lgthOld));
1182 int *tmp(new int[nbOfFaces*lgthOld+1]);
1183 int *work=tmp; *work++=INTERP_KERNEL::NORM_POLYHED;
1184 for(unsigned j=0;j<nbOfFaces;j++)
1186 INTERP_KERNEL::NormalizedCellType type;
1187 unsigned offset=cm.fillSonCellNodalConnectivity2(j,connOld+pos+1,lgthOld,work,type);
1191 std::size_t newLgth(std::distance(tmp,work)-1);//-1 for last -1
1192 connNew->pushBackValsSilent(tmp,tmp+newLgth);
1193 connNewI->pushBackSilent(connNewI->back()+(int)newLgth);
1198 connNew->pushBackValsSilent(connOld+pos,connOld+posP1);
1199 connNewI->pushBackSilent(connNewI->back()+posP1-pos);
1202 setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind.
1208 * Converts all cells to either polygons (if \a this is a 2D mesh) or
1209 * polyhedrons (if \a this is a 3D mesh).
1210 * \warning As this method is purely for user-friendliness and no optimization is
1211 * done to avoid construction of a useless vector, this method can be costly
1213 * \throw If the coordinates array is not set.
1214 * \throw If the nodal connectivity of cells is node defined.
1215 * \throw If dimension of \a this mesh is not either 2 or 3.
1217 void MEDCouplingUMesh::convertAllToPoly()
1219 int nbOfCells=getNumberOfCells();
1220 std::vector<int> cellIds(nbOfCells);
1221 for(int i=0;i<nbOfCells;i++)
1223 convertToPolyTypes(&cellIds[0],&cellIds[0]+cellIds.size());
1227 * Fixes nodal connectivity of invalid cells of type NORM_POLYHED. This method
1228 * expects that all NORM_POLYHED cells have connectivity similar to that of prismatic
1229 * volumes like NORM_HEXA8, NORM_PENTA6 etc., i.e. the first half of nodes describes a
1230 * base facet of the volume and the second half of nodes describes an opposite facet
1231 * having the same number of nodes as the base one. This method converts such
1232 * connectivity to a valid polyhedral format where connectivity of each facet is
1233 * explicitly described and connectivity of facets are separated by -1. If \a this mesh
1234 * contains a NORM_POLYHED cell with a valid connectivity, or an invalid connectivity is
1235 * not as expected, an exception is thrown and the mesh remains unchanged. Care of
1236 * a correct orientation of the first facet of a polyhedron, else orientation of a
1237 * corrected cell is reverse.<br>
1238 * This method is useful to build an extruded unstructured mesh with polyhedrons as
1239 * it releases the user from boring description of polyhedra connectivity in the valid
1241 * \throw If \a this->getMeshDimension() != 3.
1242 * \throw If \a this->getSpaceDimension() != 3.
1243 * \throw If the nodal connectivity of cells is not defined.
1244 * \throw If the coordinates array is not set.
1245 * \throw If \a this mesh contains polyhedrons with the valid connectivity.
1246 * \throw If \a this mesh contains polyhedrons with odd number of nodes.
1248 * \if ENABLE_EXAMPLES
1249 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
1250 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
1253 void MEDCouplingUMesh::convertExtrudedPolyhedra()
1255 checkFullyDefined();
1256 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1257 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
1258 int nbOfCells=getNumberOfCells();
1259 MCAuto<DataArrayInt> newCi=DataArrayInt::New();
1260 newCi->alloc(nbOfCells+1,1);
1261 int *newci=newCi->getPointer();
1262 const int *ci=_nodal_connec_index->getConstPointer();
1263 const int *c=_nodal_connec->getConstPointer();
1265 for(int i=0;i<nbOfCells;i++)
1267 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1268 if(type==INTERP_KERNEL::NORM_POLYHED)
1270 if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
1272 std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
1273 throw INTERP_KERNEL::Exception(oss.str());
1275 std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
1278 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 !";
1279 throw INTERP_KERNEL::Exception(oss.str());
1282 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)
1285 newci[i+1]=(ci[i+1]-ci[i])+newci[i];
1287 MCAuto<DataArrayInt> newC=DataArrayInt::New();
1288 newC->alloc(newci[nbOfCells],1);
1289 int *newc=newC->getPointer();
1290 for(int i=0;i<nbOfCells;i++)
1292 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1293 if(type==INTERP_KERNEL::NORM_POLYHED)
1295 std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
1296 newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
1298 for(std::size_t j=0;j<n1;j++)
1300 newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
1302 newc[n1+5*j+1]=c[ci[i]+1+j];
1303 newc[n1+5*j+2]=c[ci[i]+1+j+n1];
1304 newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
1305 newc[n1+5*j+4]=c[ci[i]+1+(j+1)%n1];
1310 newc=std::copy(c+ci[i],c+ci[i+1],newc);
1312 _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
1313 _nodal_connec->decrRef(); _nodal_connec=newC.retn();
1318 * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D
1319 * mesh) to cells of classical types. This method is opposite to convertToPolyTypes().
1320 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
1321 * to write this mesh to the MED file, its cells must be sorted using
1322 * sortCellsInMEDFileFrmt().
1323 * \warning Cells (and most notably polyhedrons) must be correctly oriented for this to work
1324 * properly. See orientCorrectlyPolyhedrons() and arePolyhedronsNotCorrectlyOriented().
1325 * \return \c true if at least one cell has been converted, \c false else. In the
1326 * last case the nodal connectivity remains unchanged.
1327 * \throw If the coordinates array is not set.
1328 * \throw If the nodal connectivity of cells is not defined.
1329 * \throw If \a this->getMeshDimension() < 0.
1331 bool MEDCouplingUMesh::unPolyze()
1333 checkFullyDefined();
1334 int mdim=getMeshDimension();
1336 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1339 int nbOfCells=getNumberOfCells();
1342 int initMeshLgth=getNodalConnectivityArrayLen();
1343 int *conn=_nodal_connec->getPointer();
1344 int *index=_nodal_connec_index->getPointer();
1349 for(int i=0;i<nbOfCells;i++)
1351 lgthOfCurCell=index[i+1]-posOfCurCell;
1352 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1353 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1354 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1358 switch(cm.getDimension())
1362 INTERP_KERNEL::AutoPtr<int> tmp=new int[lgthOfCurCell-1];
1363 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(int *)tmp);
1364 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1369 int nbOfFaces,lgthOfPolyhConn;
1370 INTERP_KERNEL::AutoPtr<int> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1371 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1376 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1380 ret=ret || (newType!=type);
1381 conn[newPos]=newType;
1383 posOfCurCell=index[i+1];
1388 std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1389 newPos+=lgthOfCurCell;
1390 posOfCurCell+=lgthOfCurCell;
1394 if(newPos!=initMeshLgth)
1395 _nodal_connec->reAlloc(newPos);
1402 * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1403 * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1404 * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells.
1406 * \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
1409 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1411 checkFullyDefined();
1412 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1413 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1414 MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1415 coords->recenterForMaxPrecision(eps);
1417 int nbOfCells=getNumberOfCells();
1418 const int *conn=_nodal_connec->getConstPointer();
1419 const int *index=_nodal_connec_index->getConstPointer();
1420 MCAuto<DataArrayInt> connINew=DataArrayInt::New();
1421 connINew->alloc(nbOfCells+1,1);
1422 int *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1423 MCAuto<DataArrayInt> connNew=DataArrayInt::New(); connNew->alloc(0,1);
1425 for(int i=0;i<nbOfCells;i++,connINewPtr++)
1427 if(conn[index[i]]==(int)INTERP_KERNEL::NORM_POLYHED)
1429 SimplifyPolyhedronCell(eps,coords,conn+index[i],conn+index[i+1],connNew);
1433 connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1434 *connINewPtr=connNew->getNumberOfTuples();
1437 setConnectivity(connNew,connINew,false);
1441 * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1442 * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1443 * the format of the returned DataArrayInt instance.
1445 * \return a newly allocated DataArrayInt sorted ascendingly of fetched node ids.
1446 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1448 DataArrayInt *MEDCouplingUMesh::computeFetchedNodeIds() const
1450 checkConnectivityFullyDefined();
1451 const int *maxEltPt(std::max_element(_nodal_connec->begin(),_nodal_connec->end()));
1452 int maxElt(maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1);
1453 std::vector<bool> retS(maxElt,false);
1454 computeNodeIdsAlg(retS);
1455 return DataArrayInt::BuildListOfSwitchedOn(retS);
1459 * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1460 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1462 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1464 int nbOfNodes((int)nodeIdsInUse.size()),nbOfCells(getNumberOfCells());
1465 const int *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1466 for(int i=0;i<nbOfCells;i++)
1467 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1470 if(conn[j]<nbOfNodes)
1471 nodeIdsInUse[conn[j]]=true;
1474 std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1475 throw INTERP_KERNEL::Exception(oss.str());
1481 * Finds nodes not used in any cell and returns an array giving a new id to every node
1482 * by excluding the unused nodes, for which the array holds -1. The result array is
1483 * a mapping in "Old to New" mode.
1484 * \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1485 * \return DataArrayInt * - a new instance of DataArrayInt. Its length is \a
1486 * this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1487 * if the node is unused or a new id else. The caller is to delete this
1488 * array using decrRef() as it is no more needed.
1489 * \throw If the coordinates array is not set.
1490 * \throw If the nodal connectivity of cells is not defined.
1491 * \throw If the nodal connectivity includes an invalid id.
1493 * \if ENABLE_EXAMPLES
1494 * \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1495 * \ref py_mcumesh_getNodeIdsInUse "Here is a Python example".
1497 * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1499 DataArrayInt *MEDCouplingUMesh::getNodeIdsInUse(int& nbrOfNodesInUse) const
1502 int nbOfNodes(getNumberOfNodes());
1503 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1504 ret->alloc(nbOfNodes,1);
1505 int *traducer=ret->getPointer();
1506 std::fill(traducer,traducer+nbOfNodes,-1);
1507 int nbOfCells=getNumberOfCells();
1508 const int *connIndex=_nodal_connec_index->getConstPointer();
1509 const int *conn=_nodal_connec->getConstPointer();
1510 for(int i=0;i<nbOfCells;i++)
1511 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1514 if(conn[j]<nbOfNodes)
1515 traducer[conn[j]]=1;
1518 std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1519 throw INTERP_KERNEL::Exception(oss.str());
1522 nbrOfNodesInUse=(int)std::count(traducer,traducer+nbOfNodes,1);
1523 std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1528 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1529 * For each cell in \b this the number of nodes constituting cell is computed.
1530 * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1531 * So for pohyhedrons some nodes can be counted several times in the returned result.
1533 * \return a newly allocated array
1534 * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1536 DataArrayInt *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1538 checkConnectivityFullyDefined();
1539 int nbOfCells=getNumberOfCells();
1540 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1541 ret->alloc(nbOfCells,1);
1542 int *retPtr=ret->getPointer();
1543 const int *conn=getNodalConnectivity()->getConstPointer();
1544 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1545 for(int i=0;i<nbOfCells;i++,retPtr++)
1547 if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1548 *retPtr=connI[i+1]-connI[i]-1;
1550 *retPtr=connI[i+1]-connI[i]-1-std::count(conn+connI[i]+1,conn+connI[i+1],-1);
1556 * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1557 * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1559 * \return DataArrayInt * - new object to be deallocated by the caller.
1560 * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1562 DataArrayInt *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1564 checkConnectivityFullyDefined();
1565 int nbOfCells=getNumberOfCells();
1566 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1567 ret->alloc(nbOfCells,1);
1568 int *retPtr=ret->getPointer();
1569 const int *conn=getNodalConnectivity()->getConstPointer();
1570 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1571 for(int i=0;i<nbOfCells;i++,retPtr++)
1573 std::set<int> s(conn+connI[i]+1,conn+connI[i+1]);
1574 if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1575 *retPtr=(int)s.size();
1579 *retPtr=(int)s.size();
1586 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1587 * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1589 * \return a newly allocated array
1591 DataArrayInt *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1593 checkConnectivityFullyDefined();
1594 int nbOfCells=getNumberOfCells();
1595 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1596 ret->alloc(nbOfCells,1);
1597 int *retPtr=ret->getPointer();
1598 const int *conn=getNodalConnectivity()->getConstPointer();
1599 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1600 for(int i=0;i<nbOfCells;i++,retPtr++,connI++)
1602 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1603 *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1609 * Removes unused nodes (the node coordinates array is shorten) and returns an array
1610 * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1611 * array mean that the corresponding old node is no more used.
1612 * \return DataArrayInt * - a new instance of DataArrayInt of length \a
1613 * this->getNumberOfNodes() before call of this method. The caller is to
1614 * delete this array using decrRef() as it is no more needed.
1615 * \throw If the coordinates array is not set.
1616 * \throw If the nodal connectivity of cells is not defined.
1617 * \throw If the nodal connectivity includes an invalid id.
1618 * \sa areAllNodesFetched
1620 * \if ENABLE_EXAMPLES
1621 * \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1622 * \ref py_mcumesh_zipCoordsTraducer "Here is a Python example".
1625 DataArrayInt *MEDCouplingUMesh::zipCoordsTraducer()
1627 return MEDCouplingPointSet::zipCoordsTraducer();
1631 * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1632 * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1634 int MEDCouplingUMesh::AreCellsEqual(const int *conn, const int *connI, int cell1, int cell2, int compType)
1639 return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1641 return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1643 return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1645 return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1647 return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1649 throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1653 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1655 int MEDCouplingUMesh::AreCellsEqualPolicy0(const int *conn, const int *connI, int cell1, int cell2)
1657 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1658 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1663 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1665 int MEDCouplingUMesh::AreCellsEqualPolicy1(const int *conn, const int *connI, int cell1, int cell2)
1667 int sz=connI[cell1+1]-connI[cell1];
1668 if(sz==connI[cell2+1]-connI[cell2])
1670 if(conn[connI[cell1]]==conn[connI[cell2]])
1672 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1673 unsigned dim=cm.getDimension();
1679 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1680 int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1681 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1682 work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1683 return work!=tmp+sz1?1:0;
1686 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1689 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1696 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1698 int MEDCouplingUMesh::AreCellsEqualPolicy2(const int *conn, const int *connI, int cell1, int cell2)
1700 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1702 if(conn[connI[cell1]]==conn[connI[cell2]])
1704 std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1705 std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1713 * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1715 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const int *conn, const int *connI, int cell1, int cell2)
1717 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1719 std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1720 std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1727 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1729 int MEDCouplingUMesh::AreCellsEqualPolicy7(const int *conn, const int *connI, int cell1, int cell2)
1731 int sz=connI[cell1+1]-connI[cell1];
1732 if(sz==connI[cell2+1]-connI[cell2])
1734 if(conn[connI[cell1]]==conn[connI[cell2]])
1736 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1737 unsigned dim=cm.getDimension();
1743 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1744 int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1745 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1746 work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1751 std::reverse_iterator<int *> it1((int *)tmp+sz1);
1752 std::reverse_iterator<int *> it2((int *)tmp);
1753 if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1759 return work!=tmp+sz1?1:0;
1762 {//case of SEG2 and SEG3
1763 if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1765 if(!cm.isQuadratic())
1767 std::reverse_iterator<const int *> it1(conn+connI[cell1+1]);
1768 std::reverse_iterator<const int *> it2(conn+connI[cell1]+1);
1769 if(std::equal(it1,it2,conn+connI[cell2]+1))
1775 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])
1782 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1789 * This method find in candidate pool defined by 'candidates' the cells equal following the polycy 'compType'.
1790 * If any true is returned and the results will be put at the end of 'result' output parameter. If not false is returned
1791 * and result remains unchanged.
1792 * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1793 * If in 'candidates' pool -1 value is considered as an empty value.
1794 * WARNING this method returns only ONE set of result !
1796 bool MEDCouplingUMesh::AreCellsEqualInPool(const std::vector<int>& candidates, int compType, const int *conn, const int *connI, DataArrayInt *result)
1798 if(candidates.size()<1)
1801 std::vector<int>::const_iterator iter=candidates.begin();
1802 int start=(*iter++);
1803 for(;iter!=candidates.end();iter++)
1805 int status=AreCellsEqual(conn,connI,start,*iter,compType);
1810 result->pushBackSilent(start);
1814 result->pushBackSilent(*iter);
1816 result->pushBackSilent(status==2?(*iter+1):-(*iter+1));
1823 * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified
1825 * This method keeps the coordiantes of \a this. This method is time consuming.
1827 * \param [in] compType input specifying the technique used to compare cells each other.
1828 * - 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.
1829 * - 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)
1830 * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1831 * - 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
1832 * can be used for users not sensitive to orientation of cell
1833 * \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.
1834 * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1835 * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1836 * \return the correspondance array old to new in a newly allocated array.
1839 void MEDCouplingUMesh::findCommonCells(int compType, int startCellId, DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr) const
1841 MCAuto<DataArrayInt> revNodal=DataArrayInt::New(),revNodalI=DataArrayInt::New();
1842 getReverseNodalConnectivity(revNodal,revNodalI);
1843 FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1846 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, int startCellId, const DataArrayInt *nodal, const DataArrayInt *nodalI, const DataArrayInt *revNodal, const DataArrayInt *revNodalI,
1847 DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr)
1849 MCAuto<DataArrayInt> commonCells=DataArrayInt::New(),commonCellsI=DataArrayInt::New(); commonCells->alloc(0,1);
1850 int nbOfCells=nodalI->getNumberOfTuples()-1;
1851 commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1852 const int *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1853 const int *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1854 std::vector<bool> isFetched(nbOfCells,false);
1857 for(int i=0;i<nbOfCells;i++)
1861 const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1862 std::vector<int> v,v2;
1863 if(connOfNode!=connPtr+connIPtr[i+1])
1865 const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1866 v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1869 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1873 const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1874 std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1875 v2.resize(std::distance(v2.begin(),it));
1879 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1881 int pos=commonCellsI->back();
1882 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1883 for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1884 isFetched[*it]=true;
1892 for(int i=startCellId;i<nbOfCells;i++)
1896 const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1897 std::vector<int> v,v2;
1898 if(connOfNode!=connPtr+connIPtr[i+1])
1900 v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1903 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1907 std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1908 v2.resize(std::distance(v2.begin(),it));
1912 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1914 int pos=commonCellsI->back();
1915 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1916 for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1917 isFetched[*it]=true;
1923 commonCellsArr=commonCells.retn();
1924 commonCellsIArr=commonCellsI.retn();
1928 * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1929 * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1930 * than \a this->getNumberOfCells() in the returned array means that there is no
1931 * corresponding cell in \a this mesh.
1932 * It is expected that \a this and \a other meshes share the same node coordinates
1933 * array, if it is not so an exception is thrown.
1934 * \param [in] other - the mesh to compare with.
1935 * \param [in] compType - specifies a cell comparison technique. For meaning of its
1936 * valid values [0,1,2], see zipConnectivityTraducer().
1937 * \param [out] arr - a new instance of DataArrayInt returning correspondence
1938 * between cells of the two meshes. It contains \a other->getNumberOfCells()
1939 * values. The caller is to delete this array using
1940 * decrRef() as it is no more needed.
1941 * \return bool - \c true if all cells of \a other mesh are present in the \a this
1944 * \if ENABLE_EXAMPLES
1945 * \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1946 * \ref py_mcumesh_areCellsIncludedIn "Here is a Python example".
1948 * \sa checkDeepEquivalOnSameNodesWith()
1949 * \sa checkGeoEquivalWith()
1951 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayInt *& arr) const
1953 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1954 int nbOfCells=getNumberOfCells();
1955 static const int possibleCompType[]={0,1,2};
1956 if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1958 std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1959 std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1961 throw INTERP_KERNEL::Exception(oss.str());
1963 MCAuto<DataArrayInt> o2n=mesh->zipConnectivityTraducer(compType,nbOfCells);
1964 arr=o2n->subArray(nbOfCells);
1965 arr->setName(other->getName());
1967 if(other->getNumberOfCells()==0)
1969 return arr->getMaxValue(tmp)<nbOfCells;
1973 * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1974 * This method tries to determine if \b other is fully included in \b this.
1975 * The main difference is that this method is not expected to throw exception.
1976 * This method has two outputs :
1978 * \param other other mesh
1979 * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1980 * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
1982 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayInt *& arr) const
1984 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1985 DataArrayInt *commonCells=0,*commonCellsI=0;
1986 int thisNbCells=getNumberOfCells();
1987 mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
1988 MCAuto<DataArrayInt> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1989 const int *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
1990 int otherNbCells=other->getNumberOfCells();
1991 MCAuto<DataArrayInt> arr2=DataArrayInt::New();
1992 arr2->alloc(otherNbCells,1);
1993 arr2->fillWithZero();
1994 int *arr2Ptr=arr2->getPointer();
1995 int nbOfCommon=commonCellsI->getNumberOfTuples()-1;
1996 for(int i=0;i<nbOfCommon;i++)
1998 int start=commonCellsPtr[commonCellsIPtr[i]];
1999 if(start<thisNbCells)
2001 for(int j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
2003 int sig=commonCellsPtr[j]>0?1:-1;
2004 int val=std::abs(commonCellsPtr[j])-1;
2005 if(val>=thisNbCells)
2006 arr2Ptr[val-thisNbCells]=sig*(start+1);
2010 arr2->setName(other->getName());
2011 if(arr2->presenceOfValue(0))
2017 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
2020 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
2021 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
2023 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
2024 std::vector<const MEDCouplingUMesh *> ms(2);
2027 return MergeUMeshesOnSameCoords(ms);
2031 * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
2032 * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
2033 * cellIds is not given explicitely but by a range python like.
2038 * \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.
2039 * \return a newly allocated
2041 * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
2042 * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
2044 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(int start, int end, int step, bool keepCoords) const
2046 if(getMeshDimension()!=-1)
2047 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
2050 int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
2052 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2054 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2056 return const_cast<MEDCouplingUMesh *>(this);
2061 * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
2062 * The result mesh shares or not the node coordinates array with \a this mesh depending
2063 * on \a keepCoords parameter.
2064 * \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
2065 * to write this mesh to the MED file, its cells must be sorted using
2066 * sortCellsInMEDFileFrmt().
2067 * \param [in] begin - an array of cell ids to include to the new mesh.
2068 * \param [in] end - a pointer to last-plus-one-th element of \a begin.
2069 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2070 * array of \a this mesh, else "free" nodes are removed from the result mesh
2071 * by calling zipCoords().
2072 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2073 * to delete this mesh using decrRef() as it is no more needed.
2074 * \throw If the coordinates array is not set.
2075 * \throw If the nodal connectivity of cells is not defined.
2076 * \throw If any cell id in the array \a begin is not valid.
2078 * \if ENABLE_EXAMPLES
2079 * \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
2080 * \ref py_mcumesh_buildPartOfMySelf "Here is a Python example".
2083 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const int *begin, const int *end, bool keepCoords) const
2085 if(getMeshDimension()!=-1)
2086 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
2090 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2092 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2094 return const_cast<MEDCouplingUMesh *>(this);
2099 * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
2101 * 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.
2102 * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
2103 * The number of cells of \b this will remain the same with this method.
2105 * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
2106 * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
2107 * \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 ).
2108 * Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
2110 void MEDCouplingUMesh::setPartOfMySelf(const int *cellIdsBg, const int *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2112 checkConnectivityFullyDefined();
2113 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2114 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2115 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2116 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2118 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2119 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2120 throw INTERP_KERNEL::Exception(oss.str());
2122 int nbOfCellsToModify=(int)std::distance(cellIdsBg,cellIdsEnd);
2123 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2125 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2126 throw INTERP_KERNEL::Exception(oss.str());
2128 int nbOfCells=getNumberOfCells();
2129 bool easyAssign=true;
2130 const int *connI=_nodal_connec_index->getConstPointer();
2131 const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2132 for(const int *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2134 if(*it>=0 && *it<nbOfCells)
2136 easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2140 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2141 throw INTERP_KERNEL::Exception(oss.str());
2146 MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2151 DataArrayInt *arrOut=0,*arrIOut=0;
2152 MEDCouplingUMesh::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2154 MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2155 setConnectivity(arrOut,arrIOut,true);
2159 void MEDCouplingUMesh::setPartOfMySelfSlice(int start, int end, int step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2161 checkConnectivityFullyDefined();
2162 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2163 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2164 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2165 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2167 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2168 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2169 throw INTERP_KERNEL::Exception(oss.str());
2171 int nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2172 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2174 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2175 throw INTERP_KERNEL::Exception(oss.str());
2177 int nbOfCells=getNumberOfCells();
2178 bool easyAssign=true;
2179 const int *connI=_nodal_connec_index->getConstPointer();
2180 const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2182 for(int i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2184 if(it>=0 && it<nbOfCells)
2186 easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2190 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2191 throw INTERP_KERNEL::Exception(oss.str());
2196 MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2201 DataArrayInt *arrOut=0,*arrIOut=0;
2202 MEDCouplingUMesh::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2204 MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2205 setConnectivity(arrOut,arrIOut,true);
2210 * Keeps from \a this only cells which constituing point id are in the ids specified by [ \a begin,\a end ).
2211 * The resulting cell ids are stored at the end of the 'cellIdsKept' parameter.
2212 * Parameter \a fullyIn specifies if a cell that has part of its nodes in ids array is kept or not.
2213 * If \a fullyIn is true only cells whose ids are \b fully contained in [ \a begin,\a end ) tab will be kept.
2215 * \param [in] begin input start of array of node ids.
2216 * \param [in] end input end of array of node ids.
2217 * \param [in] fullyIn input that specifies if all node ids must be in [ \a begin,\a end ) array to consider cell to be in.
2218 * \param [in,out] cellIdsKeptArr array where all candidate cell ids are put at the end.
2220 void MEDCouplingUMesh::fillCellIdsToKeepFromNodeIds(const int *begin, const int *end, bool fullyIn, DataArrayInt *&cellIdsKeptArr) const
2222 MCAuto<DataArrayInt> cellIdsKept=DataArrayInt::New(); cellIdsKept->alloc(0,1);
2223 checkConnectivityFullyDefined();
2225 int sz=getNodalConnectivity()->getMaxValue(tmp); sz=std::max(sz,0)+1;
2226 std::vector<bool> fastFinder(sz,false);
2227 for(const int *work=begin;work!=end;work++)
2228 if(*work>=0 && *work<sz)
2229 fastFinder[*work]=true;
2230 int nbOfCells=getNumberOfCells();
2231 const int *conn=getNodalConnectivity()->getConstPointer();
2232 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2233 for(int i=0;i<nbOfCells;i++)
2235 int ref=0,nbOfHit=0;
2236 for(const int *work2=conn+connIndex[i]+1;work2!=conn+connIndex[i+1];work2++)
2240 if(fastFinder[*work2])
2243 if((ref==nbOfHit && fullyIn) || (nbOfHit!=0 && !fullyIn))
2244 cellIdsKept->pushBackSilent(i);
2246 cellIdsKeptArr=cellIdsKept.retn();
2250 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2251 * this->getMeshDimension(), that bound some cells of \a this mesh.
2252 * The cells of lower dimension to include to the result mesh are selected basing on
2253 * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2254 * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2255 * ==\c false, a cell is copied if any its node is in the array of node ids. The
2256 * created mesh shares the node coordinates array with \a this mesh.
2257 * \param [in] begin - the array of node ids.
2258 * \param [in] end - a pointer to the (last+1)-th element of \a begin.
2259 * \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2260 * array \a begin are added, else cells whose any node is in the
2261 * array \a begin are added.
2262 * \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2263 * to delete this mesh using decrRef() as it is no more needed.
2264 * \throw If the coordinates array is not set.
2265 * \throw If the nodal connectivity of cells is not defined.
2266 * \throw If any node id in \a begin is not valid.
2268 * \if ENABLE_EXAMPLES
2269 * \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2270 * \ref py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2273 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const int *begin, const int *end, bool fullyIn) const
2275 MCAuto<DataArrayInt> desc,descIndx,revDesc,revDescIndx;
2276 desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=DataArrayInt::New(); revDescIndx=DataArrayInt::New();
2277 MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2278 desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2279 return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2283 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2284 * this->getMeshDimension(), which bound only one cell of \a this mesh.
2285 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2286 * array of \a this mesh, else "free" nodes are removed from the result mesh
2287 * by calling zipCoords().
2288 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2289 * to delete this mesh using decrRef() as it is no more needed.
2290 * \throw If the coordinates array is not set.
2291 * \throw If the nodal connectivity of cells is not defined.
2293 * \if ENABLE_EXAMPLES
2294 * \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2295 * \ref py_mcumesh_buildBoundaryMesh "Here is a Python example".
2298 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2300 DataArrayInt *desc=DataArrayInt::New();
2301 DataArrayInt *descIndx=DataArrayInt::New();
2302 DataArrayInt *revDesc=DataArrayInt::New();
2303 DataArrayInt *revDescIndx=DataArrayInt::New();
2305 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2308 descIndx->decrRef();
2309 int nbOfCells=meshDM1->getNumberOfCells();
2310 const int *revDescIndxC=revDescIndx->getConstPointer();
2311 std::vector<int> boundaryCells;
2312 for(int i=0;i<nbOfCells;i++)
2313 if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2314 boundaryCells.push_back(i);
2315 revDescIndx->decrRef();
2316 MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2321 * This method returns a newly created DataArrayInt instance containing ids of cells located in boundary.
2322 * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2323 * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2325 DataArrayInt *MEDCouplingUMesh::findCellIdsOnBoundary() const
2327 checkFullyDefined();
2328 MCAuto<DataArrayInt> desc=DataArrayInt::New();
2329 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2330 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2331 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2333 buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2334 desc=(DataArrayInt*)0; descIndx=(DataArrayInt*)0;
2336 MCAuto<DataArrayInt> tmp=revDescIndx->deltaShiftIndex();
2337 MCAuto<DataArrayInt> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayInt*)0;
2338 const int *revDescPtr=revDesc->getConstPointer();
2339 const int *revDescIndxPtr=revDescIndx->getConstPointer();
2340 int nbOfCells=getNumberOfCells();
2341 std::vector<bool> ret1(nbOfCells,false);
2343 for(const int *pt=faceIds->begin();pt!=faceIds->end();pt++)
2344 if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2345 { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2347 DataArrayInt *ret2=DataArrayInt::New();
2349 int *ret2Ptr=ret2->getPointer();
2351 for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2354 ret2->setName("BoundaryCells");
2359 * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2360 * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2361 * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2362 * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2364 * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2365 * 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
2366 * equals a cell in \b otherDimM1OnSameCoords.
2368 * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2369 * are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2371 * \param [in] otherDimM1OnSameCoords
2372 * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2373 * \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
2374 * cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2376 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *&cellIdsRk0, DataArrayInt *&cellIdsRk1) const
2378 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2379 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2380 checkConnectivityFullyDefined();
2381 otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2382 if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2383 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2384 MCAuto<DataArrayInt> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2385 MCAuto<DataArrayInt> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2386 MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2387 MCAuto<DataArrayInt> descThisPart=DataArrayInt::New(),descIThisPart=DataArrayInt::New(),revDescThisPart=DataArrayInt::New(),revDescIThisPart=DataArrayInt::New();
2388 MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2389 const int *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2390 DataArrayInt *idsOtherInConsti=0;
2391 bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2392 MCAuto<DataArrayInt> idsOtherInConstiAuto(idsOtherInConsti);
2394 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2396 for(const int *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2397 s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2398 MCAuto<DataArrayInt> s1arr_renum1=DataArrayInt::New(); s1arr_renum1->alloc((int)s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2399 s1arr_renum1->sort();
2400 cellIdsRk0=s0arr.retn();
2401 //cellIdsRk1=s_renum1.retn();
2402 cellIdsRk1=s1arr_renum1.retn();
2406 * 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
2407 * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2409 * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2411 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2413 MCAuto<DataArrayInt> desc=DataArrayInt::New();
2414 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2415 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2416 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2418 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2419 revDesc=0; desc=0; descIndx=0;
2420 MCAuto<DataArrayInt> revDescIndx2=revDescIndx->deltaShiftIndex();
2421 MCAuto<DataArrayInt> part=revDescIndx2->findIdsEqual(1);
2422 return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2426 * Finds nodes lying on the boundary of \a this mesh.
2427 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of found
2428 * nodes. The caller is to delete this array using decrRef() as it is no
2430 * \throw If the coordinates array is not set.
2431 * \throw If the nodal connectivity of cells is node defined.
2433 * \if ENABLE_EXAMPLES
2434 * \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2435 * \ref py_mcumesh_findBoundaryNodes "Here is a Python example".
2438 DataArrayInt *MEDCouplingUMesh::findBoundaryNodes() const
2440 MCAuto<MEDCouplingUMesh> skin=computeSkin();
2441 return skin->computeFetchedNodeIds();
2444 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2447 return const_cast<MEDCouplingUMesh *>(this);
2451 * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2452 * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2453 * 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.
2454 * 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.
2455 * 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.
2457 * \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
2458 * parameter is altered during the call.
2459 * \param [out] nodeIdsToDuplicate node ids needed to be duplicated following the algorithm explain above.
2460 * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2461 * \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.
2463 * \warning This method modifies param \b otherDimM1OnSameCoords (for speed reasons).
2465 void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *& nodeIdsToDuplicate,
2466 DataArrayInt *& cellIdsNeededToBeRenum, DataArrayInt *& cellIdsNotModified) const
2468 typedef MCAuto<DataArrayInt> DAInt;
2469 typedef MCAuto<MEDCouplingUMesh> MCUMesh;
2471 checkFullyDefined();
2472 otherDimM1OnSameCoords.checkFullyDefined();
2473 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2474 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2475 if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2476 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2478 // Checking star-shaped M1 group:
2479 DAInt dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2480 MCUMesh meshM2 = otherDimM1OnSameCoords.buildDescendingConnectivity(dt0, dit0, rdt0, rdit0);
2481 DAInt dsi = rdit0->deltaShiftIndex();
2482 DAInt idsTmp0 = dsi->findIdsNotInRange(-1, 3);
2483 if(idsTmp0->getNumberOfTuples())
2484 throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2485 dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2487 // Get extreme nodes from the group (they won't be duplicated), ie nodes belonging to boundary cells of M1
2488 DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2489 MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2490 DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2491 // Remove from the list points on the boundary of the M0 mesh (those need duplication!)
2492 dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2493 MCUMesh m0desc = buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0;
2494 dsi = rdit0->deltaShiftIndex();
2495 DAInt boundSegs = dsi->findIdsEqual(1); // boundary segs/faces of the M0 mesh
2496 MCUMesh m0descSkin = static_cast<MEDCouplingUMesh *>(m0desc->buildPartOfMySelf(boundSegs->begin(),boundSegs->end(), true));
2497 DAInt fNodes = m0descSkin->computeFetchedNodeIds();
2498 // In 3D, some points on the boundary of M0 still need duplication:
2500 if (getMeshDimension() == 3)
2502 DAInt dnu1=DataArrayInt::New(), dnu2=DataArrayInt::New(), dnu3=DataArrayInt::New(), dnu4=DataArrayInt::New();
2503 MCUMesh m0descSkinDesc = m0descSkin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4);
2504 dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2505 DataArrayInt * corresp=0;
2506 meshM2->areCellsIncludedIn(m0descSkinDesc,2,corresp);
2507 DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2509 if (validIds->getNumberOfTuples())
2511 MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0descSkinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2512 DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2513 DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2514 notDup = xtrem->buildSubstraction(fNodes1);
2517 notDup = xtrem->buildSubstraction(fNodes);
2520 notDup = xtrem->buildSubstraction(fNodes);
2522 // Now compute cells around group (i.e. cells where we will do the propagation to identify the two sub-sets delimited by the group)
2523 DAInt m1Nodes = otherDimM1OnSameCoords.computeFetchedNodeIds();
2524 DAInt dupl = m1Nodes->buildSubstraction(notDup);
2525 DAInt cellsAroundGroup = getCellIdsLyingOnNodes(dupl->begin(), dupl->end(), false); // false= take cell in, even if not all nodes are in notDup
2528 MCUMesh m0Part2=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroup->begin(),cellsAroundGroup->end(),true));
2529 int nCells2 = m0Part2->getNumberOfCells();
2530 DAInt desc00=DataArrayInt::New(),descI00=DataArrayInt::New(),revDesc00=DataArrayInt::New(),revDescI00=DataArrayInt::New();
2531 MCUMesh m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00);
2533 // Neighbor information of the mesh without considering the crack (serves to count how many connex pieces it is made of)
2534 DataArrayInt *tmp00=0,*tmp11=0;
2535 MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00, tmp00, tmp11);
2536 DAInt neighInit00(tmp00);
2537 DAInt neighIInit00(tmp11);
2538 // Neighbor information of the mesh WITH the crack (some neighbors are removed):
2539 DataArrayInt *idsTmp=0;
2540 bool b=m01->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsTmp);
2542 // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2543 // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2544 MEDCouplingUMesh::RemoveIdsFromIndexedArrays(ids->begin(),ids->end(),desc00,descI00);
2545 DataArrayInt *tmp0=0,*tmp1=0;
2546 // Compute the neighbor of each cell in m0Part2, taking into account the broken link above. Two
2547 // cells on either side of the crack (defined by the mesh of low dimension) are not neighbor anymore.
2548 ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00,tmp0,tmp1);
2549 DAInt neigh00(tmp0);
2550 DAInt neighI00(tmp1);
2552 // For each initial connex part of the sub-mesh (or said differently for each independent crack):
2553 int seed = 0, nIter = 0;
2554 int nIterMax = nCells2+1; // Safety net for the loop
2555 DAInt hitCells = DataArrayInt::New(); hitCells->alloc(nCells2);
2556 hitCells->fillWithValue(-1);
2557 DAInt cellsToModifyConn0_torenum = DataArrayInt::New();
2558 cellsToModifyConn0_torenum->alloc(0,1);
2559 while (nIter < nIterMax)
2561 DAInt t = hitCells->findIdsEqual(-1);
2562 if (!t->getNumberOfTuples())
2564 // Connex zone without the crack (to compute the next seed really)
2566 DAInt connexCheck = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neighInit00,neighIInit00, -1, dnu);
2568 for (int * ptr = connexCheck->getPointer(); cnt < connexCheck->getNumberOfTuples(); ptr++, cnt++)
2569 hitCells->setIJ(*ptr,0,1);
2570 // Connex zone WITH the crack (to identify cells lying on either part of the crack)
2571 DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neigh00,neighI00, -1, dnu);
2572 cellsToModifyConn0_torenum = DataArrayInt::Aggregate(cellsToModifyConn0_torenum, spreadZone, 0);
2573 // Compute next seed, i.e. a cell in another connex part, which was not covered by the previous iterations
2574 DAInt comple = cellsToModifyConn0_torenum->buildComplement(nCells2);
2575 DAInt nonHitCells = hitCells->findIdsEqual(-1);
2576 DAInt intersec = nonHitCells->buildIntersection(comple);
2577 if (intersec->getNumberOfTuples())
2578 { seed = intersec->getIJ(0,0); }
2583 if (nIter >= nIterMax)
2584 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate(): internal error - too many iterations.");
2586 DAInt cellsToModifyConn1_torenum=cellsToModifyConn0_torenum->buildComplement(neighI00->getNumberOfTuples()-1);
2587 cellsToModifyConn0_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2588 cellsToModifyConn1_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2590 cellIdsNeededToBeRenum=cellsToModifyConn0_torenum.retn();
2591 cellIdsNotModified=cellsToModifyConn1_torenum.retn();
2592 nodeIdsToDuplicate=dupl.retn();
2596 * This method operates a modification of the connectivity and coords in \b this.
2597 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2598 * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2599 * 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
2600 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2601 * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2603 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2605 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2606 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2608 void MEDCouplingUMesh::duplicateNodes(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd)
2610 int nbOfNodes=getNumberOfNodes();
2611 duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2612 duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2616 * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2617 * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2619 * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2621 * \sa renumberNodesInConn
2623 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(int offset)
2625 checkConnectivityFullyDefined();
2626 int *conn(getNodalConnectivity()->getPointer());
2627 const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2628 int nbOfCells(getNumberOfCells());
2629 for(int i=0;i<nbOfCells;i++)
2630 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2632 int& node=conn[iconn];
2633 if(node>=0)//avoid polyhedron separator
2638 _nodal_connec->declareAsNew();
2643 * Same than renumberNodesInConn(const int *) except that here the format of old-to-new traducer is using map instead
2644 * 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
2647 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<int,int>& newNodeNumbersO2N)
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
2659 INTERP_KERNEL::HashMap<int,int>::const_iterator it(newNodeNumbersO2N.find(node));
2660 if(it!=newNodeNumbersO2N.end())
2666 std::ostringstream oss; oss << "MEDCouplingUMesh::renumberNodesInConn(map) : presence in connectivity for cell #" << i << " of node #" << node << " : Not in map !";
2667 throw INTERP_KERNEL::Exception(oss.str());
2671 _nodal_connec->declareAsNew();
2676 * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2677 * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2678 * This method is a generalization of shiftNodeNumbersInConn().
2679 * \warning This method performs no check of validity of new ids. **Use it with care !**
2680 * \param [in] newNodeNumbersO2N - a permutation array, of length \a
2681 * this->getNumberOfNodes(), in "Old to New" mode.
2682 * See \ref numbering for more info on renumbering modes.
2683 * \throw If the nodal connectivity of cells is not defined.
2685 * \if ENABLE_EXAMPLES
2686 * \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2687 * \ref py_mcumesh_renumberNodesInConn "Here is a Python example".
2690 void MEDCouplingUMesh::renumberNodesInConn(const int *newNodeNumbersO2N)
2692 checkConnectivityFullyDefined();
2693 int *conn=getNodalConnectivity()->getPointer();
2694 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2695 int nbOfCells(getNumberOfCells());
2696 for(int i=0;i<nbOfCells;i++)
2697 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2699 int& node=conn[iconn];
2700 if(node>=0)//avoid polyhedron separator
2702 node=newNodeNumbersO2N[node];
2705 _nodal_connec->declareAsNew();
2710 * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2711 * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2712 * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2714 * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2716 void MEDCouplingUMesh::shiftNodeNumbersInConn(int delta)
2718 checkConnectivityFullyDefined();
2719 int *conn=getNodalConnectivity()->getPointer();
2720 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2721 int nbOfCells=getNumberOfCells();
2722 for(int i=0;i<nbOfCells;i++)
2723 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2725 int& node=conn[iconn];
2726 if(node>=0)//avoid polyhedron separator
2731 _nodal_connec->declareAsNew();
2736 * This method operates a modification of the connectivity in \b this.
2737 * 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.
2738 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2739 * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2740 * 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
2741 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2742 * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2744 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2745 * As an another consequense after the call of this method \b this can be transiently non cohrent.
2747 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2748 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2749 * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ).
2751 void MEDCouplingUMesh::duplicateNodesInConn(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd, int offset)
2753 checkConnectivityFullyDefined();
2754 std::map<int,int> m;
2756 for(const int *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2758 int *conn=getNodalConnectivity()->getPointer();
2759 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2760 int nbOfCells=getNumberOfCells();
2761 for(int i=0;i<nbOfCells;i++)
2762 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2764 int& node=conn[iconn];
2765 if(node>=0)//avoid polyhedron separator
2767 std::map<int,int>::iterator it=m.find(node);
2776 * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2778 * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2779 * After the call of this method the number of cells remains the same as before.
2781 * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2782 * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2783 * be strictly in [0;this->getNumberOfCells()).
2785 * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2786 * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2787 * should be contained in[0;this->getNumberOfCells()).
2789 * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2792 void MEDCouplingUMesh::renumberCells(const int *old2NewBg, bool check)
2794 checkConnectivityFullyDefined();
2795 int nbCells=getNumberOfCells();
2796 const int *array=old2NewBg;
2798 array=DataArrayInt::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2800 const int *conn=_nodal_connec->getConstPointer();
2801 const int *connI=_nodal_connec_index->getConstPointer();
2802 MCAuto<DataArrayInt> o2n=DataArrayInt::New(); o2n->useArray(array,false,C_DEALLOC,nbCells,1);
2803 MCAuto<DataArrayInt> n2o=o2n->invertArrayO2N2N2O(nbCells);
2804 const int *n2oPtr=n2o->begin();
2805 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
2806 newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2807 newConn->copyStringInfoFrom(*_nodal_connec);
2808 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
2809 newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2810 newConnI->copyStringInfoFrom(*_nodal_connec_index);
2812 int *newC=newConn->getPointer();
2813 int *newCI=newConnI->getPointer();
2816 for(int i=0;i<nbCells;i++)
2819 int nbOfElts=connI[pos+1]-connI[pos];
2820 newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2825 setConnectivity(newConn,newConnI);
2827 free(const_cast<int *>(array));
2831 * Finds cells whose bounding boxes intersect a given bounding box.
2832 * \param [in] bbox - an array defining the bounding box via coordinates of its
2833 * extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2835 * \param [in] eps - a factor used to increase size of the bounding box of cell
2836 * before comparing it with \a bbox. This factor is multiplied by the maximal
2837 * extent of the bounding box of cell to produce an addition to this bounding box.
2838 * \return DataArrayInt * - a new instance of DataArrayInt holding ids for found
2839 * cells. The caller is to delete this array using decrRef() as it is no more
2841 * \throw If the coordinates array is not set.
2842 * \throw If the nodal connectivity of cells is not defined.
2844 * \if ENABLE_EXAMPLES
2845 * \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2846 * \ref py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2849 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2851 MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2852 if(getMeshDimension()==-1)
2854 elems->pushBackSilent(0);
2855 return elems.retn();
2857 int dim=getSpaceDimension();
2858 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2859 const int* conn = getNodalConnectivity()->getConstPointer();
2860 const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2861 const double* coords = getCoords()->getConstPointer();
2862 int nbOfCells=getNumberOfCells();
2863 for ( int ielem=0; ielem<nbOfCells;ielem++ )
2865 for (int i=0; i<dim; i++)
2867 elem_bb[i*2]=std::numeric_limits<double>::max();
2868 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2871 for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2873 int node= conn[inode];
2874 if(node>=0)//avoid polyhedron separator
2876 for (int idim=0; idim<dim; idim++)
2878 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2880 elem_bb[idim*2] = coords[node*dim+idim] ;
2882 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2884 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2889 if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2890 elems->pushBackSilent(ielem);
2892 return elems.retn();
2896 * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2897 * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2898 * added in 'elems' parameter.
2900 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2902 MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2903 if(getMeshDimension()==-1)
2905 elems->pushBackSilent(0);
2906 return elems.retn();
2908 int dim=getSpaceDimension();
2909 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2910 const int* conn = getNodalConnectivity()->getConstPointer();
2911 const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2912 const double* coords = getCoords()->getConstPointer();
2913 int nbOfCells=getNumberOfCells();
2914 for ( int ielem=0; ielem<nbOfCells;ielem++ )
2916 for (int i=0; i<dim; i++)
2918 elem_bb[i*2]=std::numeric_limits<double>::max();
2919 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2922 for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2924 int node= conn[inode];
2925 if(node>=0)//avoid polyhedron separator
2927 for (int idim=0; idim<dim; idim++)
2929 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2931 elem_bb[idim*2] = coords[node*dim+idim] ;
2933 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2935 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2940 if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
2941 elems->pushBackSilent(ielem);
2943 return elems.retn();
2947 * Returns a type of a cell by its id.
2948 * \param [in] cellId - the id of the cell of interest.
2949 * \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
2950 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2952 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(int cellId) const
2954 const int *ptI=_nodal_connec_index->getConstPointer();
2955 const int *pt=_nodal_connec->getConstPointer();
2956 if(cellId>=0 && cellId<(int)_nodal_connec_index->getNbOfElems()-1)
2957 return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2960 std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2961 throw INTERP_KERNEL::Exception(oss.str());
2966 * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2967 * This method does not throw exception if geometric type \a type is not in \a this.
2968 * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2969 * The coordinates array is not considered here.
2971 * \param [in] type the geometric type
2972 * \return cell ids in this having geometric type \a type.
2974 DataArrayInt *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2977 MCAuto<DataArrayInt> ret=DataArrayInt::New();
2979 checkConnectivityFullyDefined();
2980 int nbCells=getNumberOfCells();
2981 int mdim=getMeshDimension();
2982 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
2983 if(mdim!=(int)cm.getDimension())
2984 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
2985 const int *ptI=_nodal_connec_index->getConstPointer();
2986 const int *pt=_nodal_connec->getConstPointer();
2987 for(int i=0;i<nbCells;i++)
2989 if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
2990 ret->pushBackSilent(i);
2996 * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
2998 int MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
3000 const int *ptI=_nodal_connec_index->getConstPointer();
3001 const int *pt=_nodal_connec->getConstPointer();
3002 int nbOfCells=getNumberOfCells();
3004 for(int i=0;i<nbOfCells;i++)
3005 if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
3011 * Returns the nodal connectivity of a given cell.
3012 * The separator of faces within polyhedron connectivity (-1) is not returned, thus
3013 * all returned node ids can be used in getCoordinatesOfNode().
3014 * \param [in] cellId - an id of the cell of interest.
3015 * \param [in,out] conn - a vector where the node ids are appended. It is not
3016 * cleared before the appending.
3017 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
3019 void MEDCouplingUMesh::getNodeIdsOfCell(int cellId, std::vector<int>& conn) const
3021 const int *ptI=_nodal_connec_index->getConstPointer();
3022 const int *pt=_nodal_connec->getConstPointer();
3023 for(const int *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
3028 std::string MEDCouplingUMesh::simpleRepr() const
3030 static const char msg0[]="No coordinates specified !";
3031 std::ostringstream ret;
3032 ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
3033 ret << "Description of mesh : \"" << getDescription() << "\"\n";
3035 double tt=getTime(tmpp1,tmpp2);
3036 ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
3037 ret << "Iteration : " << tmpp1 << " Order : " << tmpp2 << "\n";
3039 { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
3041 { ret << " Mesh dimension has not been set or is invalid !"; }
3044 const int spaceDim=getSpaceDimension();
3045 ret << spaceDim << "\nInfo attached on space dimension : ";
3046 for(int i=0;i<spaceDim;i++)
3047 ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
3051 ret << msg0 << "\n";
3052 ret << "Number of nodes : ";
3054 ret << getNumberOfNodes() << "\n";
3056 ret << msg0 << "\n";
3057 ret << "Number of cells : ";
3058 if(_nodal_connec!=0 && _nodal_connec_index!=0)
3059 ret << getNumberOfCells() << "\n";
3061 ret << "No connectivity specified !" << "\n";
3062 ret << "Cell types present : ";
3063 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
3065 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
3066 ret << cm.getRepr() << " ";
3072 std::string MEDCouplingUMesh::advancedRepr() const
3074 std::ostringstream ret;
3075 ret << simpleRepr();
3076 ret << "\nCoordinates array : \n___________________\n\n";
3078 _coords->reprWithoutNameStream(ret);
3080 ret << "No array set !\n";
3081 ret << "\n\nConnectivity arrays : \n_____________________\n\n";
3082 reprConnectivityOfThisLL(ret);
3087 * This method returns a C++ code that is a dump of \a this.
3088 * This method will throw if this is not fully defined.
3090 std::string MEDCouplingUMesh::cppRepr() const
3092 static const char coordsName[]="coords";
3093 static const char connName[]="conn";
3094 static const char connIName[]="connI";
3095 checkFullyDefined();
3096 std::ostringstream ret; ret << "// coordinates" << std::endl;
3097 _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
3098 _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
3099 _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
3100 ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
3101 ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
3102 ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
3103 ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
3107 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
3109 std::ostringstream ret;
3110 reprConnectivityOfThisLL(ret);
3115 * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsability to deal with.
3116 * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
3117 * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
3120 * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
3121 * 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
3122 * with number of tuples set to 0, if not the array is taken as this in the returned instance.
3124 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(int spaceDim) const
3126 int mdim=getMeshDimension();
3128 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
3129 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
3130 MCAuto<DataArrayInt> tmp1,tmp2;
3131 bool needToCpyCT=true;
3134 tmp1=DataArrayInt::New(); tmp1->alloc(0,1);
3142 if(!_nodal_connec_index)
3144 tmp2=DataArrayInt::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
3149 tmp2=_nodal_connec_index;
3152 ret->setConnectivity(tmp1,tmp2,false);
3157 MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
3158 ret->setCoords(coords);
3161 ret->setCoords(_coords);
3165 void MEDCouplingUMesh::reprConnectivityOfThisLL(std::ostringstream& stream) const
3167 if(_nodal_connec!=0 && _nodal_connec_index!=0)
3169 int nbOfCells=getNumberOfCells();
3170 const int *c=_nodal_connec->getConstPointer();
3171 const int *ci=_nodal_connec_index->getConstPointer();
3172 for(int i=0;i<nbOfCells;i++)
3174 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[i]]);
3175 stream << "Cell #" << i << " " << cm.getRepr() << " : ";
3176 std::copy(c+ci[i]+1,c+ci[i+1],std::ostream_iterator<int>(stream," "));
3181 stream << "Connectivity not defined !\n";
3184 int MEDCouplingUMesh::getNumberOfNodesInCell(int cellId) const
3186 const int *ptI=_nodal_connec_index->getConstPointer();
3187 const int *pt=_nodal_connec->getConstPointer();
3188 if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
3189 return ptI[cellId+1]-ptI[cellId]-1;
3191 return (int)std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind2nd(std::not_equal_to<int>(),-1));
3195 * Returns types of cells of the specified part of \a this mesh.
3196 * This method avoids computing sub-mesh explicitely to get its types.
3197 * \param [in] begin - an array of cell ids of interest.
3198 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3199 * \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3200 * describing the cell types.
3201 * \throw If the coordinates array is not set.
3202 * \throw If the nodal connectivity of cells is not defined.
3203 * \sa getAllGeoTypes()
3205 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const int *begin, const int *end) const
3207 checkFullyDefined();
3208 std::set<INTERP_KERNEL::NormalizedCellType> ret;
3209 const int *conn=_nodal_connec->getConstPointer();
3210 const int *connIndex=_nodal_connec_index->getConstPointer();
3211 for(const int *w=begin;w!=end;w++)
3212 ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3217 * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3218 * Optionally updates
3219 * a set of types of cells constituting \a this mesh.
3220 * This method is for advanced users having prepared their connectivity before. For
3221 * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3222 * \param [in] conn - the nodal connectivity array.
3223 * \param [in] connIndex - the nodal connectivity index array.
3224 * \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3227 void MEDCouplingUMesh::setConnectivity(DataArrayInt *conn, DataArrayInt *connIndex, bool isComputingTypes)
3229 DataArrayInt::SetArrayIn(conn,_nodal_connec);
3230 DataArrayInt::SetArrayIn(connIndex,_nodal_connec_index);
3231 if(isComputingTypes)
3237 * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3238 * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3240 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCopy):MEDCouplingPointSet(other,deepCopy),_mesh_dim(other._mesh_dim),
3241 _nodal_connec(0),_nodal_connec_index(0),
3242 _types(other._types)
3244 if(other._nodal_connec)
3245 _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCopy);
3246 if(other._nodal_connec_index)
3247 _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCopy);
3250 MEDCouplingUMesh::~MEDCouplingUMesh()
3253 _nodal_connec->decrRef();
3254 if(_nodal_connec_index)
3255 _nodal_connec_index->decrRef();
3259 * Recomputes a set of cell types of \a this mesh. For more info see
3260 * \ref MEDCouplingUMeshNodalConnectivity.
3262 void MEDCouplingUMesh::computeTypes()
3264 ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3268 * This method checks that all arrays are set. If yes nothing done if no an exception is thrown.
3270 void MEDCouplingUMesh::checkFullyDefined() const
3272 if(!_nodal_connec_index || !_nodal_connec || !_coords)
3273 throw INTERP_KERNEL::Exception("Reverse nodal connectivity computation requires full connectivity and coordinates set in unstructured mesh.");
3277 * This method checks that all connectivity arrays are set. If yes nothing done if no an exception is thrown.
3279 void MEDCouplingUMesh::checkConnectivityFullyDefined() const
3281 if(!_nodal_connec_index || !_nodal_connec)
3282 throw INTERP_KERNEL::Exception("Reverse nodal connectivity computation requires full connectivity set in unstructured mesh.");
3286 * Returns a number of cells constituting \a this mesh.
3287 * \return int - the number of cells in \a this mesh.
3288 * \throw If the nodal connectivity of cells is not defined.
3290 int MEDCouplingUMesh::getNumberOfCells() const
3292 if(_nodal_connec_index)
3293 return _nodal_connec_index->getNumberOfTuples()-1;
3298 throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3302 * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3303 * mesh. For more info see \ref meshes.
3304 * \return int - the dimension of \a this mesh.
3305 * \throw If the mesh dimension is not defined using setMeshDimension().
3307 int MEDCouplingUMesh::getMeshDimension() const
3310 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3315 * Returns a length of the nodal connectivity array.
3316 * This method is for test reason. Normally the integer returned is not useable by
3317 * user. For more info see \ref MEDCouplingUMeshNodalConnectivity.
3318 * \return int - the length of the nodal connectivity array.
3320 int MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3322 return _nodal_connec->getNbOfElems();
3326 * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3328 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<int>& tinyInfo, std::vector<std::string>& littleStrings) const
3330 MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3331 tinyInfo.push_back(getMeshDimension());
3332 tinyInfo.push_back(getNumberOfCells());
3334 tinyInfo.push_back(getNodalConnectivityArrayLen());
3336 tinyInfo.push_back(-1);
3340 * First step of unserialization process.
3342 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<int>& tinyInfo) const
3344 return tinyInfo[6]<=0;
3348 * Second step of serialization process.
3349 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3352 * \param littleStrings
3354 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<int>& tinyInfo, DataArrayInt *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3356 MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3358 a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3362 * Third and final step of serialization process.
3364 void MEDCouplingUMesh::serialize(DataArrayInt *&a1, DataArrayDouble *&a2) const
3366 MEDCouplingPointSet::serialize(a1,a2);
3367 if(getMeshDimension()>-1)
3369 a1=DataArrayInt::New();
3370 a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3371 int *ptA1=a1->getPointer();
3372 const int *conn=getNodalConnectivity()->getConstPointer();
3373 const int *index=getNodalConnectivityIndex()->getConstPointer();
3374 ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3375 std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3382 * Second and final unserialization process.
3383 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3385 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<int>& tinyInfo, const DataArrayInt *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3387 MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3388 setMeshDimension(tinyInfo[5]);
3392 const int *recvBuffer=a1->getConstPointer();
3393 MCAuto<DataArrayInt> myConnecIndex=DataArrayInt::New();
3394 myConnecIndex->alloc(tinyInfo[6]+1,1);
3395 std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3396 MCAuto<DataArrayInt> myConnec=DataArrayInt::New();
3397 myConnec->alloc(tinyInfo[7],1);
3398 std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3399 setConnectivity(myConnec, myConnecIndex);
3404 * This is the low algorithm of MEDCouplingUMesh::buildPartOfMySelfSlice.
3405 * CellIds are given using range specified by a start an end and step.
3407 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice(int start, int end, int step) const
3409 checkFullyDefined();
3410 int ncell=getNumberOfCells();
3411 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New();
3412 ret->_mesh_dim=_mesh_dim;
3413 ret->setCoords(_coords);
3414 int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice : ");
3415 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(newNbOfCells+1,1);
3416 int *newConnIPtr=newConnI->getPointer(); *newConnIPtr=0;
3418 const int *conn=_nodal_connec->getConstPointer();
3419 const int *connIndex=_nodal_connec_index->getConstPointer();
3420 for(int i=0;i<newNbOfCells;i++,newConnIPtr++,work+=step)
3422 if(work>=0 && work<ncell)
3424 newConnIPtr[1]=newConnIPtr[0]+connIndex[work+1]-connIndex[work];
3428 std::ostringstream oss; oss << "MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice : On pos #" << i << " input cell id =" << work << " should be in [0," << ncell << ") !";
3429 throw INTERP_KERNEL::Exception(oss.str());
3432 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(newConnIPtr[0],1);
3433 int *newConnPtr=newConn->getPointer();
3434 std::set<INTERP_KERNEL::NormalizedCellType> types;
3436 for(int i=0;i<newNbOfCells;i++,newConnIPtr++,work+=step)
3438 types.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[work]]);
3439 newConnPtr=std::copy(conn+connIndex[work],conn+connIndex[work+1],newConnPtr);
3441 ret->setConnectivity(newConn,newConnI,false);
3443 ret->copyTinyInfoFrom(this);
3448 * This is the low algorithm of MEDCouplingUMesh::buildPartOfMySelf.
3449 * Keeps from \a this only cells which constituing point id are in the ids specified by [ \a begin,\a end ).
3450 * The return newly allocated mesh will share the same coordinates as \a this.
3452 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfKeepCoords(const int *begin, const int *end) const
3454 checkConnectivityFullyDefined();
3455 int ncell=getNumberOfCells();
3456 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New();
3457 ret->_mesh_dim=_mesh_dim;
3458 ret->setCoords(_coords);
3459 std::size_t nbOfElemsRet=std::distance(begin,end);
3460 int *connIndexRet=(int *)malloc((nbOfElemsRet+1)*sizeof(int));
3462 const int *conn=_nodal_connec->getConstPointer();
3463 const int *connIndex=_nodal_connec_index->getConstPointer();
3465 for(const int *work=begin;work!=end;work++,newNbring++)
3467 if(*work>=0 && *work<ncell)
3468 connIndexRet[newNbring+1]=connIndexRet[newNbring]+connIndex[*work+1]-connIndex[*work];
3472 std::ostringstream oss; oss << "MEDCouplingUMesh::buildPartOfMySelfKeepCoords : On pos #" << std::distance(begin,work) << " input cell id =" << *work << " should be in [0," << ncell << ") !";
3473 throw INTERP_KERNEL::Exception(oss.str());
3476 int *connRet=(int *)malloc(connIndexRet[nbOfElemsRet]*sizeof(int));
3477 int *connRetWork=connRet;
3478 std::set<INTERP_KERNEL::NormalizedCellType> types;
3479 for(const int *work=begin;work!=end;work++)
3481 types.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*work]]);
3482 connRetWork=std::copy(conn+connIndex[*work],conn+connIndex[*work+1],connRetWork);
3484 MCAuto<DataArrayInt> connRetArr=DataArrayInt::New();
3485 connRetArr->useArray(connRet,true,C_DEALLOC,connIndexRet[nbOfElemsRet],1);
3486 MCAuto<DataArrayInt> connIndexRetArr=DataArrayInt::New();
3487 connIndexRetArr->useArray(connIndexRet,true,C_DEALLOC,(int)nbOfElemsRet+1,1);
3488 ret->setConnectivity(connRetArr,connIndexRetArr,false);
3490 ret->copyTinyInfoFrom(this);
3495 * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3497 * For 1D cells, the returned field contains lengths.<br>
3498 * For 2D cells, the returned field contains areas.<br>
3499 * For 3D cells, the returned field contains volumes.
3500 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3501 * orientation, i.e. the volume is always positive.
3502 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3503 * and one time . The caller is to delete this field using decrRef() as it is no
3506 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3508 std::string name="MeasureOfMesh_";
3510 int nbelem=getNumberOfCells();
3511 MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3512 field->setName(name);
3513 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3514 array->alloc(nbelem,1);
3515 double *area_vol=array->getPointer();
3516 field->setArray(array) ; array=0;
3517 field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3518 field->synchronizeTimeWithMesh();
3519 if(getMeshDimension()!=-1)
3522 INTERP_KERNEL::NormalizedCellType type;
3523 int dim_space=getSpaceDimension();
3524 const double *coords=getCoords()->getConstPointer();
3525 const int *connec=getNodalConnectivity()->getConstPointer();
3526 const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3527 for(int iel=0;iel<nbelem;iel++)
3529 ipt=connec_index[iel];
3530 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3531 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);
3534 std::transform(area_vol,area_vol+nbelem,area_vol,std::ptr_fun<double,double>(fabs));
3538 area_vol[0]=std::numeric_limits<double>::max();
3540 return field.retn();
3544 * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3546 * For 1D cells, the returned array contains lengths.<br>
3547 * For 2D cells, the returned array contains areas.<br>
3548 * For 3D cells, the returned array contains volumes.
3549 * This method avoids building explicitly a part of \a this mesh to perform the work.
3550 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3551 * orientation, i.e. the volume is always positive.
3552 * \param [in] begin - an array of cell ids of interest.
3553 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3554 * \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3555 * delete this array using decrRef() as it is no more needed.
3557 * \if ENABLE_EXAMPLES
3558 * \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3559 * \ref py_mcumesh_getPartMeasureField "Here is a Python example".
3561 * \sa getMeasureField()
3563 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const int *begin, const int *end) const
3565 std::string name="PartMeasureOfMesh_";
3567 int nbelem=(int)std::distance(begin,end);
3568 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3569 array->setName(name);
3570 array->alloc(nbelem,1);
3571 double *area_vol=array->getPointer();
3572 if(getMeshDimension()!=-1)
3575 INTERP_KERNEL::NormalizedCellType type;
3576 int dim_space=getSpaceDimension();
3577 const double *coords=getCoords()->getConstPointer();
3578 const int *connec=getNodalConnectivity()->getConstPointer();
3579 const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3580 for(const int *iel=begin;iel!=end;iel++)
3582 ipt=connec_index[*iel];
3583 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3584 *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<int,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3587 std::transform(array->getPointer(),area_vol,array->getPointer(),std::ptr_fun<double,double>(fabs));
3591 area_vol[0]=std::numeric_limits<double>::max();
3593 return array.retn();
3597 * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3598 * \a this one. The returned field contains the dual cell volume for each corresponding
3599 * node in \a this mesh. In other words, the field returns the getMeasureField() of
3600 * the dual mesh in P1 sens of \a this.<br>
3601 * For 1D cells, the returned field contains lengths.<br>
3602 * For 2D cells, the returned field contains areas.<br>
3603 * For 3D cells, the returned field contains volumes.
3604 * This method is useful to check "P1*" conservative interpolators.
3605 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3606 * orientation, i.e. the volume is always positive.
3607 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3608 * nodes and one time. The caller is to delete this array using decrRef() as
3609 * it is no more needed.
3611 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3613 MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3614 std::string name="MeasureOnNodeOfMesh_";
3616 int nbNodes=getNumberOfNodes();
3617 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3618 double cst=1./((double)getMeshDimension()+1.);
3619 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3620 array->alloc(nbNodes,1);
3621 double *valsToFill=array->getPointer();
3622 std::fill(valsToFill,valsToFill+nbNodes,0.);
3623 const double *values=tmp->getArray()->getConstPointer();
3624 MCAuto<DataArrayInt> da=DataArrayInt::New();
3625 MCAuto<DataArrayInt> daInd=DataArrayInt::New();
3626 getReverseNodalConnectivity(da,daInd);
3627 const int *daPtr=da->getConstPointer();
3628 const int *daIPtr=daInd->getConstPointer();
3629 for(int i=0;i<nbNodes;i++)
3630 for(const int *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3631 valsToFill[i]+=cst*values[*cell];
3633 ret->setArray(array);
3638 * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3639 * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3640 * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3641 * and are normalized.
3642 * <br> \a this can be either
3643 * - a 2D mesh in 2D or 3D space or
3644 * - an 1D mesh in 2D space.
3646 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3647 * cells and one time. The caller is to delete this field using decrRef() as
3648 * it is no more needed.
3649 * \throw If the nodal connectivity of cells is not defined.
3650 * \throw If the coordinates array is not set.
3651 * \throw If the mesh dimension is not set.
3652 * \throw If the mesh and space dimension is not as specified above.
3654 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3656 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3657 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3658 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3659 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3660 int nbOfCells=getNumberOfCells();
3661 int nbComp=getMeshDimension()+1;
3662 array->alloc(nbOfCells,nbComp);
3663 double *vals=array->getPointer();
3664 const int *connI=_nodal_connec_index->getConstPointer();
3665 const int *conn=_nodal_connec->getConstPointer();
3666 const double *coords=_coords->getConstPointer();
3667 if(getMeshDimension()==2)
3669 if(getSpaceDimension()==3)
3671 MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3672 const double *locPtr=loc->getConstPointer();
3673 for(int i=0;i<nbOfCells;i++,vals+=3)
3675 int offset=connI[i];
3676 INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3677 double n=INTERP_KERNEL::norm<3>(vals);
3678 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3683 MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3684 const double *isAbsPtr=isAbs->getArray()->begin();
3685 for(int i=0;i<nbOfCells;i++,isAbsPtr++)
3686 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3689 else//meshdimension==1
3692 for(int i=0;i<nbOfCells;i++)
3694 int offset=connI[i];
3695 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3696 double n=INTERP_KERNEL::norm<2>(tmp);
3697 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3702 ret->setArray(array);
3704 ret->synchronizeTimeWithSupport();
3709 * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3710 * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3711 * and are normalized.
3712 * <br> \a this can be either
3713 * - a 2D mesh in 2D or 3D space or
3714 * - an 1D mesh in 2D space.
3716 * This method avoids building explicitly a part of \a this mesh to perform the work.
3717 * \param [in] begin - an array of cell ids of interest.
3718 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3719 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3720 * cells and one time. The caller is to delete this field using decrRef() as
3721 * it is no more needed.
3722 * \throw If the nodal connectivity of cells is not defined.
3723 * \throw If the coordinates array is not set.
3724 * \throw If the mesh dimension is not set.
3725 * \throw If the mesh and space dimension is not as specified above.
3726 * \sa buildOrthogonalField()
3728 * \if ENABLE_EXAMPLES
3729 * \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3730 * \ref py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3733 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const int *begin, const int *end) const
3735 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3736 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3737 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3738 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3739 std::size_t nbelems=std::distance(begin,end);
3740 int nbComp=getMeshDimension()+1;
3741 array->alloc((int)nbelems,nbComp);
3742 double *vals=array->getPointer();
3743 const int *connI=_nodal_connec_index->getConstPointer();
3744 const int *conn=_nodal_connec->getConstPointer();
3745 const double *coords=_coords->getConstPointer();
3746 if(getMeshDimension()==2)
3748 if(getSpaceDimension()==3)
3750 MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3751 const double *locPtr=loc->getConstPointer();
3752 for(const int *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3754 int offset=connI[*i];
3755 INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3756 double n=INTERP_KERNEL::norm<3>(vals);
3757 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3762 for(std::size_t i=0;i<nbelems;i++)
3763 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3766 else//meshdimension==1
3769 for(const int *i=begin;i!=end;i++)
3771 int offset=connI[*i];
3772 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3773 double n=INTERP_KERNEL::norm<2>(tmp);
3774 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3779 ret->setArray(array);
3781 ret->synchronizeTimeWithSupport();
3786 * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3787 * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3788 * and are \b not normalized.
3789 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3790 * cells and one time. The caller is to delete this field using decrRef() as
3791 * it is no more needed.
3792 * \throw If the nodal connectivity of cells is not defined.
3793 * \throw If the coordinates array is not set.
3794 * \throw If \a this->getMeshDimension() != 1.
3795 * \throw If \a this mesh includes cells of type other than SEG2.
3797 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3799 if(getMeshDimension()!=1)
3800 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3801 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3802 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3803 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3804 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3805 int nbOfCells=getNumberOfCells();
3806 int spaceDim=getSpaceDimension();
3807 array->alloc(nbOfCells,spaceDim);
3808 double *pt=array->getPointer();
3809 const double *coo=getCoords()->getConstPointer();
3810 std::vector<int> conn;
3812 for(int i=0;i<nbOfCells;i++)
3815 getNodeIdsOfCell(i,conn);
3816 pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3818 ret->setArray(array);
3820 ret->synchronizeTimeWithSupport();
3825 * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3826 * returns a new DataArrayInt, of length equal to the number of 2D cells in the result
3827 * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3828 * from. If a result face is shared by two 3D cells, then the face in included twice in
3830 * \param [in] origin - 3 components of a point defining location of the plane.
3831 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3832 * must be greater than 1e-6.
3833 * \param [in] eps - half-thickness of the plane.
3834 * \param [out] cellIds - a new instance of DataArrayInt holding ids of 3D cells
3835 * producing correspondent 2D cells. The caller is to delete this array
3836 * using decrRef() as it is no more needed.
3837 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3838 * not share the node coordinates array with \a this mesh. The caller is to
3839 * delete this mesh using decrRef() as it is no more needed.
3840 * \throw If the coordinates array is not set.
3841 * \throw If the nodal connectivity of cells is not defined.
3842 * \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3843 * \throw If magnitude of \a vec is less than 1e-6.
3844 * \throw If the plane does not intersect any 3D cell of \a this mesh.
3845 * \throw If \a this includes quadratic cells.
3847 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3849 checkFullyDefined();
3850 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3851 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3852 MCAuto<DataArrayInt> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3853 if(candidates->empty())
3854 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3855 std::vector<int> nodes;
3856 DataArrayInt *cellIds1D=0;
3857 MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3858 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3859 MCAuto<DataArrayInt> desc1=DataArrayInt::New(),desc2=DataArrayInt::New();
3860 MCAuto<DataArrayInt> descIndx1=DataArrayInt::New(),descIndx2=DataArrayInt::New();
3861 MCAuto<DataArrayInt> revDesc1=DataArrayInt::New(),revDesc2=DataArrayInt::New();
3862 MCAuto<DataArrayInt> revDescIndx1=DataArrayInt::New(),revDescIndx2=DataArrayInt::New();
3863 MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3864 revDesc2=0; revDescIndx2=0;
3865 MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3866 revDesc1=0; revDescIndx1=0;
3867 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3868 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3870 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3871 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3873 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3874 std::vector< std::pair<int,int> > cut3DSurf(mDesc2->getNumberOfCells());
3875 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3876 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3877 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3878 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New());
3879 connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3880 subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3881 if(cellIds2->empty())
3882 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3883 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3884 ret->setCoords(mDesc1->getCoords());
3885 ret->setConnectivity(conn,connI,true);
3886 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3891 * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3892 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
3893 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3895 * \param [in] origin - 3 components of a point defining location of the plane.
3896 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3897 * must be greater than 1e-6.
3898 * \param [in] eps - half-thickness of the plane.
3899 * \param [out] cellIds - a new instance of DataArrayInt holding ids of faces
3900 * producing correspondent segments. The caller is to delete this array
3901 * using decrRef() as it is no more needed.
3902 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3903 * mesh in 3D space. This mesh does not share the node coordinates array with
3904 * \a this mesh. The caller is to delete this mesh using decrRef() as it is
3906 * \throw If the coordinates array is not set.
3907 * \throw If the nodal connectivity of cells is not defined.
3908 * \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3909 * \throw If magnitude of \a vec is less than 1e-6.
3910 * \throw If the plane does not intersect any 2D cell of \a this mesh.
3911 * \throw If \a this includes quadratic cells.
3913 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3915 checkFullyDefined();
3916 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3917 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3918 MCAuto<DataArrayInt> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3919 if(candidates->empty())
3920 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3921 std::vector<int> nodes;
3922 DataArrayInt *cellIds1D=0;
3923 MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3924 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3925 MCAuto<DataArrayInt> desc1=DataArrayInt::New();
3926 MCAuto<DataArrayInt> descIndx1=DataArrayInt::New();
3927 MCAuto<DataArrayInt> revDesc1=DataArrayInt::New();
3928 MCAuto<DataArrayInt> revDescIndx1=DataArrayInt::New();
3929 MCAuto<MEDCouplingUMesh> mDesc1=subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3930 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3931 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3933 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3934 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3936 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3937 int ncellsSub=subMesh->getNumberOfCells();
3938 std::vector< std::pair<int,int> > cut3DSurf(ncellsSub);
3939 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3940 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3941 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3942 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New()); connI->pushBackSilent(0);
3944 const int *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3945 const int *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3946 for(int i=0;i<ncellsSub;i++)
3948 if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3950 if(cut3DSurf[i].first!=-2)
3952 conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3953 connI->pushBackSilent(conn->getNumberOfTuples());
3954 cellIds2->pushBackSilent(i);
3958 int cellId3DSurf=cut3DSurf[i].second;
3959 int offset=nodalI[cellId3DSurf]+1;
3960 int nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3961 for(int j=0;j<nbOfEdges;j++)
3963 conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3964 connI->pushBackSilent(conn->getNumberOfTuples());
3965 cellIds2->pushBackSilent(cellId3DSurf);
3970 if(cellIds2->empty())
3971 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3972 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3973 ret->setCoords(mDesc1->getCoords());
3974 ret->setConnectivity(conn,connI,true);
3975 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3980 * Finds cells whose bounding boxes intersect a given plane.
3981 * \param [in] origin - 3 components of a point defining location of the plane.
3982 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3983 * must be greater than 1e-6.
3984 * \param [in] eps - half-thickness of the plane.
3985 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of the found
3986 * cells. The caller is to delete this array using decrRef() as it is no more
3988 * \throw If the coordinates array is not set.
3989 * \throw If the nodal connectivity of cells is not defined.
3990 * \throw If \a this->getSpaceDimension() != 3.
3991 * \throw If magnitude of \a vec is less than 1e-6.
3992 * \sa buildSlice3D()
3994 DataArrayInt *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
3996 checkFullyDefined();
3997 if(getSpaceDimension()!=3)
3998 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
3999 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
4001 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
4003 vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
4004 double angle=acos(vec[2]/normm);
4005 MCAuto<DataArrayInt> cellIds;
4009 MCAuto<DataArrayDouble> coo=_coords->deepCopy();
4010 double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
4011 if(normm2/normm>1e-6)
4012 DataArrayDouble::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer(),coo->getPointer());
4013 MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
4015 mw->getBoundingBox(bbox);
4016 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
4017 cellIds=mw->getCellsInBoundingBox(bbox,eps);
4021 getBoundingBox(bbox);
4022 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
4023 cellIds=getCellsInBoundingBox(bbox,eps);
4025 return cellIds.retn();
4029 * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
4030 * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
4031 * No consideration of coordinate is done by this method.
4032 * 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)
4033 * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be usefull.
4035 bool MEDCouplingUMesh::isContiguous1D() const
4037 if(getMeshDimension()!=1)
4038 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
4039 int nbCells=getNumberOfCells();
4041 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
4042 const int *connI=_nodal_connec_index->getConstPointer();
4043 const int *conn=_nodal_connec->getConstPointer();
4044 int ref=conn[connI[0]+2];
4045 for(int i=1;i<nbCells;i++)
4047 if(conn[connI[i]+1]!=ref)
4049 ref=conn[connI[i]+2];
4055 * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
4056 * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
4057 * \param pt reference point of the line
4058 * \param v normalized director vector of the line
4059 * \param eps max precision before throwing an exception
4060 * \param res output of size this->getNumberOfCells
4062 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
4064 if(getMeshDimension()!=1)
4065 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
4066 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
4067 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
4068 if(getSpaceDimension()!=3)
4069 throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
4070 MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
4071 const double *fPtr=f->getArray()->getConstPointer();
4073 for(int i=0;i<getNumberOfCells();i++)
4075 const double *tmp1=fPtr+3*i;
4076 tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
4077 tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
4078 tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
4079 double n1=INTERP_KERNEL::norm<3>(tmp);
4080 n1/=INTERP_KERNEL::norm<3>(tmp1);
4082 throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
4084 const double *coo=getCoords()->getConstPointer();
4085 for(int i=0;i<getNumberOfNodes();i++)
4087 std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
4088 std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
4089 res[i]=std::accumulate(tmp,tmp+3,0.);
4094 * 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.
4095 * \a this is expected to be a mesh so that its space dimension is equal to its
4096 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4097 * 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).
4099 * 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
4100 * 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).
4101 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4103 * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
4104 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4106 * \param [in] ptBg the start pointer (included) of the coordinates of the point
4107 * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
4108 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4109 * \return the positive value of the distance.
4110 * \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
4112 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
4114 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, int& cellId) const
4116 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4117 if(meshDim!=spaceDim-1)
4118 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
4119 if(meshDim!=2 && meshDim!=1)
4120 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
4121 checkFullyDefined();
4122 if((int)std::distance(ptBg,ptEnd)!=spaceDim)
4123 { 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()); }
4124 DataArrayInt *ret1=0;
4125 MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,C_DEALLOC,1,spaceDim);
4126 MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
4127 MCAuto<DataArrayInt> ret1Safe(ret1);
4128 cellId=*ret1Safe->begin();
4129 return *ret0->begin();
4133 * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
4134 * to \a this and the first \a cellId in \a this corresponding to the returned distance.
4135 * 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
4136 * 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).
4137 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4139 * \a this is expected to be a mesh so that its space dimension is equal to its
4140 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4141 * 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).
4143 * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
4144 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4146 * \param [in] pts the list of points in which each tuple represents a point
4147 * \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.
4148 * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
4149 * \throw if number of components of \a pts is not equal to the space dimension.
4150 * \throw if mesh dimension of \a this is not equal to space dimension - 1.
4151 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
4153 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayInt *& cellIds) const
4156 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
4157 pts->checkAllocated();
4158 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4159 if(meshDim!=spaceDim-1)
4160 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
4161 if(meshDim!=2 && meshDim!=1)
4162 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
4163 if(pts->getNumberOfComponents()!=spaceDim)
4165 std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
4166 throw INTERP_KERNEL::Exception(oss.str());
4168 checkFullyDefined();
4169 int nbCells=getNumberOfCells();
4171 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
4172 int nbOfPts=pts->getNumberOfTuples();
4173 MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
4174 MCAuto<DataArrayInt> ret1=DataArrayInt::New(); ret1->alloc(nbOfPts,1);
4175 const int *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
4176 double *ret0Ptr=ret0->getPointer(); int *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
4177 MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
4178 const double *bbox(bboxArr->begin());
4183 BBTreeDst<3> myTree(bbox,0,0,nbCells);
4184 for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
4186 double x=std::numeric_limits<double>::max();
4187 std::vector<int> elems;
4188 myTree.getMinDistanceOfMax(ptsPtr,x);
4189 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4190 DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4196 BBTreeDst<2> myTree(bbox,0,0,nbCells);
4197 for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4199 double x=std::numeric_limits<double>::max();
4200 std::vector<int> elems;
4201 myTree.getMinDistanceOfMax(ptsPtr,x);
4202 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4203 DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4208 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4210 cellIds=ret1.retn();
4217 * \param [in] pt the start pointer (included) of the coordinates of the point
4218 * \param [in] cellIdsBg the start pointer (included) of cellIds
4219 * \param [in] cellIdsEnd the end pointer (excluded) of cellIds
4220 * \param [in] nc nodal connectivity
4221 * \param [in] ncI nodal connectivity index
4222 * \param [in,out] ret0 the min distance between \a this and the external input point
4223 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4224 * \sa MEDCouplingUMesh::distanceToPoint, MEDCouplingUMesh::distanceToPoints
4226 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)
4229 ret0=std::numeric_limits<double>::max();
4230 for(const int *zeCell=cellIdsBg;zeCell!=cellIdsEnd;zeCell++)
4232 switch((INTERP_KERNEL::NormalizedCellType)nc[ncI[*zeCell]])
4234 case INTERP_KERNEL::NORM_TRI3:
4236 double tmp=INTERP_KERNEL::DistanceFromPtToTriInSpaceDim3(pt,coords+3*nc[ncI[*zeCell]+1],coords+3*nc[ncI[*zeCell]+2],coords+3*nc[ncI[*zeCell]+3]);
4238 { ret0=tmp; cellId=*zeCell; }
4241 case INTERP_KERNEL::NORM_QUAD4:
4242 case INTERP_KERNEL::NORM_POLYGON:
4244 double tmp=INTERP_KERNEL::DistanceFromPtToPolygonInSpaceDim3(pt,nc+ncI[*zeCell]+1,nc+ncI[*zeCell+1],coords);
4246 { ret0=tmp; cellId=*zeCell; }
4250 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint3DSurfAlg : not managed cell type ! Supporting TRI3, QUAD4 and POLYGON !");
4256 * \param [in] pt the start pointer (included) of the coordinates of the point
4257 * \param [in] cellIdsBg the start pointer (included) of cellIds
4258 * \param [in] cellIdsEnd the end pointer (excluded) of cellIds
4259 * \param [in] nc nodal connectivity
4260 * \param [in] ncI nodal connectivity index
4261 * \param [in,out] ret0 the min distance between \a this and the external input point
4262 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4263 * \sa MEDCouplingUMesh::distanceToPoint, MEDCouplingUMesh::distanceToPoints
4265 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)
4268 ret0=std::numeric_limits<double>::max();
4269 for(const int *zeCell=cellIdsBg;zeCell!=cellIdsEnd;zeCell++)
4271 switch((INTERP_KERNEL::NormalizedCellType)nc[ncI[*zeCell]])
4273 case INTERP_KERNEL::NORM_SEG2:
4275 std::size_t uselessEntry=0;
4276 double tmp=INTERP_KERNEL::SquareDistanceFromPtToSegInSpaceDim2(pt,coords+2*nc[ncI[*zeCell]+1],coords+2*nc[ncI[*zeCell]+2],uselessEntry);
4279 { ret0=tmp; cellId=*zeCell; }
4283 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint2DCurveAlg : not managed cell type ! Supporting SEG2 !");
4290 * Finds cells in contact with a ball (i.e. a point with precision).
4291 * 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.
4292 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4294 * \warning This method is suitable if the caller intends to evaluate only one
4295 * point, for more points getCellsContainingPoints() is recommended as it is
4297 * \param [in] pos - array of coordinates of the ball central point.
4298 * \param [in] eps - ball radius.
4299 * \return int - a smallest id of cells being in contact with the ball, -1 in case
4300 * if there are no such cells.
4301 * \throw If the coordinates array is not set.
4302 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4304 int MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4306 std::vector<int> elts;
4307 getCellsContainingPoint(pos,eps,elts);
4310 return elts.front();
4314 * Finds cells in contact with a ball (i.e. a point with precision).
4315 * 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.
4316 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4317 * \warning This method is suitable if the caller intends to evaluate only one
4318 * point, for more points getCellsContainingPoints() is recommended as it is
4320 * \param [in] pos - array of coordinates of the ball central point.
4321 * \param [in] eps - ball radius.
4322 * \param [out] elts - vector returning ids of the found cells. It is cleared
4323 * before inserting ids.
4324 * \throw If the coordinates array is not set.
4325 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4327 * \if ENABLE_EXAMPLES
4328 * \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4329 * \ref py_mcumesh_getCellsContainingPoint "Here is a Python example".
4332 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<int>& elts) const
4334 MCAuto<DataArrayInt> eltsUg,eltsIndexUg;
4335 getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4336 elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4341 namespace MEDCoupling
4343 template<const int SPACEDIMM>
4347 static const int MY_SPACEDIM=SPACEDIMM;
4348 static const int MY_MESHDIM=8;
4349 typedef int MyConnType;
4350 static const INTERP_KERNEL::NumberingPolicy My_numPol=INTERP_KERNEL::ALL_C_MODE;
4352 // useless, but for windows compilation ...
4353 const double* getCoordinatesPtr() const { return 0; }
4354 const int* getConnectivityPtr() const { return 0; }
4355 const int* getConnectivityIndexPtr() const { return 0; }
4356 INTERP_KERNEL::NormalizedCellType getTypeOfElement(int) const { return (INTERP_KERNEL::NormalizedCellType)0; }
4360 INTERP_KERNEL::Edge *MEDCouplingUMeshBuildQPFromEdge2(INTERP_KERNEL::NormalizedCellType typ, const int *bg, const double *coords2D, std::map< MCAuto<INTERP_KERNEL::Node>,int>& m)
4362 INTERP_KERNEL::Edge *ret(0);
4363 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]));
4364 m[n0]=bg[0]; m[n1]=bg[1];
4367 case INTERP_KERNEL::NORM_SEG2:
4369 ret=new INTERP_KERNEL::EdgeLin(n0,n1);
4372 case INTERP_KERNEL::NORM_SEG3:
4374 INTERP_KERNEL::Node *n2(new INTERP_KERNEL::Node(coords2D[2*bg[2]],coords2D[2*bg[2]+1])); m[n2]=bg[2];
4375 INTERP_KERNEL::EdgeLin *e1(new INTERP_KERNEL::EdgeLin(n0,n2)),*e2(new INTERP_KERNEL::EdgeLin(n2,n1));
4376 INTERP_KERNEL::SegSegIntersector inters(*e1,*e2);
4377 // is the SEG3 degenerated, and thus can be reduced to a SEG2?
4378 bool colinearity(inters.areColinears());
4379 delete e1; delete e2;
4381 { ret=new INTERP_KERNEL::EdgeLin(n0,n1); }
4383 { ret=new INTERP_KERNEL::EdgeArcCircle(n0,n2,n1); }
4387 throw INTERP_KERNEL::Exception("MEDCouplingUMeshBuildQPFromEdge2 : Expecting a mesh with spaceDim==2 and meshDim==1 !");
4392 INTERP_KERNEL::Edge *MEDCouplingUMeshBuildQPFromEdge(INTERP_KERNEL::NormalizedCellType typ, std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >& mapp2, const int *bg)
4394 INTERP_KERNEL::Edge *ret=0;
4397 case INTERP_KERNEL::NORM_SEG2:
4399 ret=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[1]].first);
4402 case INTERP_KERNEL::NORM_SEG3:
4404 INTERP_KERNEL::EdgeLin *e1=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[2]].first);
4405 INTERP_KERNEL::EdgeLin *e2=new INTERP_KERNEL::EdgeLin(mapp2[bg[2]].first,mapp2[bg[1]].first);
4406 INTERP_KERNEL::SegSegIntersector inters(*e1,*e2);
4407 // is the SEG3 degenerated, and thus can be reduced to a SEG2?
4408 bool colinearity=inters.areColinears();
4409 delete e1; delete e2;
4411 ret=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[1]].first);
4413 ret=new INTERP_KERNEL::EdgeArcCircle(mapp2[bg[0]].first,mapp2[bg[2]].first,mapp2[bg[1]].first);
4414 mapp2[bg[2]].second=false;
4418 throw INTERP_KERNEL::Exception("MEDCouplingUMeshBuildQPFromEdge : Expecting a mesh with spaceDim==2 and meshDim==1 !");
4424 * This method creates a sub mesh in Geometric2D DS. The sub mesh is composed by the sub set of cells in 'candidates' taken from
4425 * the global mesh 'mDesc'.
4426 * The input mesh 'mDesc' must be so that mDim==1 and spaceDim==2.
4427 * 'mapp' returns a mapping between local numbering in submesh (represented by a Node*) and the global node numbering in 'mDesc'.
4429 INTERP_KERNEL::QuadraticPolygon *MEDCouplingUMeshBuildQPFromMesh(const MEDCouplingUMesh *mDesc, const std::vector<int>& candidates,
4430 std::map<INTERP_KERNEL::Node *,int>& mapp)
4433 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.
4434 const double *coo=mDesc->getCoords()->getConstPointer();
4435 const int *c=mDesc->getNodalConnectivity()->getConstPointer();
4436 const int *cI=mDesc->getNodalConnectivityIndex()->getConstPointer();
4438 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
4439 s.insert(c+cI[*it]+1,c+cI[(*it)+1]);
4440 for(std::set<int>::const_iterator it2=s.begin();it2!=s.end();it2++)
4442 INTERP_KERNEL::Node *n=new INTERP_KERNEL::Node(coo[2*(*it2)],coo[2*(*it2)+1]);
4443 mapp2[*it2]=std::pair<INTERP_KERNEL::Node *,bool>(n,true);
4445 INTERP_KERNEL::QuadraticPolygon *ret=new INTERP_KERNEL::QuadraticPolygon;
4446 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
4448 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[*it]];
4449 ret->pushBack(MEDCouplingUMeshBuildQPFromEdge(typ,mapp2,c+cI[*it]+1));
4451 for(std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >::const_iterator it2=mapp2.begin();it2!=mapp2.end();it2++)
4453 if((*it2).second.second)
4454 mapp[(*it2).second.first]=(*it2).first;
4455 ((*it2).second.first)->decrRef();
4460 INTERP_KERNEL::Node *MEDCouplingUMeshBuildQPNode(int nodeId, const double *coo1, int offset1, const double *coo2, int offset2, const std::vector<double>& addCoo)
4464 int locId=nodeId-offset2;
4465 return new INTERP_KERNEL::Node(addCoo[2*locId],addCoo[2*locId+1]);
4469 int locId=nodeId-offset1;
4470 return new INTERP_KERNEL::Node(coo2[2*locId],coo2[2*locId+1]);
4472 return new INTERP_KERNEL::Node(coo1[2*nodeId],coo1[2*nodeId+1]);
4476 * Construct a mapping between set of Nodes and the standart MEDCoupling connectivity format (c, cI).
4478 void MEDCouplingUMeshBuildQPFromMesh3(const double *coo1, int offset1, const double *coo2, int offset2, const std::vector<double>& addCoo,
4479 const int *desc1Bg, const int *desc1End, const std::vector<std::vector<int> >& intesctEdges1,
4480 /*output*/std::map<INTERP_KERNEL::Node *,int>& mapp, std::map<int,INTERP_KERNEL::Node *>& mappRev)
4482 for(const int *desc1=desc1Bg;desc1!=desc1End;desc1++)
4484 int eltId1=abs(*desc1)-1;
4485 for(std::vector<int>::const_iterator it1=intesctEdges1[eltId1].begin();it1!=intesctEdges1[eltId1].end();it1++)
4487 std::map<int,INTERP_KERNEL::Node *>::const_iterator it=mappRev.find(*it1);
4488 if(it==mappRev.end())
4490 INTERP_KERNEL::Node *node=MEDCouplingUMeshBuildQPNode(*it1,coo1,offset1,coo2,offset2,addCoo);
4501 template<int SPACEDIM>
4502 void MEDCouplingUMesh::getCellsContainingPointsAlg(const double *coords, const double *pos, int nbOfPoints,
4503 double eps, MCAuto<DataArrayInt>& elts, MCAuto<DataArrayInt>& eltsIndex) const
4505 elts=DataArrayInt::New(); eltsIndex=DataArrayInt::New(); eltsIndex->alloc(nbOfPoints+1,1); eltsIndex->setIJ(0,0,0); elts->alloc(0,1);
4506 int *eltsIndexPtr(eltsIndex->getPointer());
4507 MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree(eps));
4508 const double *bbox(bboxArr->begin());
4509 int nbOfCells=getNumberOfCells();
4510 const int *conn=_nodal_connec->getConstPointer();
4511 const int *connI=_nodal_connec_index->getConstPointer();
4512 double bb[2*SPACEDIM];
4513 BBTree<SPACEDIM,int> myTree(&bbox[0],0,0,nbOfCells,-eps);
4514 for(int i=0;i<nbOfPoints;i++)
4516 eltsIndexPtr[i+1]=eltsIndexPtr[i];
4517 for(int j=0;j<SPACEDIM;j++)
4519 bb[2*j]=pos[SPACEDIM*i+j];
4520 bb[2*j+1]=pos[SPACEDIM*i+j];
4522 std::vector<int> candidates;
4523 myTree.getIntersectingElems(bb,candidates);
4524 for(std::vector<int>::const_iterator iter=candidates.begin();iter!=candidates.end();iter++)
4526 int sz(connI[(*iter)+1]-connI[*iter]-1);
4527 INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[connI[*iter]]);
4529 if(ct!=INTERP_KERNEL::NORM_POLYGON && ct!=INTERP_KERNEL::NORM_QPOLYG)
4530 status=INTERP_KERNEL::PointLocatorAlgos<DummyClsMCUG<SPACEDIM> >::isElementContainsPoint(pos+i*SPACEDIM,ct,coords,conn+connI[*iter]+1,sz,eps);
4534 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPointsAlg : not implemented yet for POLYGON and QPOLYGON in spaceDim 3 !");
4535 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
4536 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
4537 std::vector<INTERP_KERNEL::Node *> nodes(sz);
4538 INTERP_KERNEL::QuadraticPolygon *pol(0);
4539 for(int j=0;j<sz;j++)
4541 int nodeId(conn[connI[*iter]+1+j]);
4542 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*SPACEDIM],coords[nodeId*SPACEDIM+1]);
4544 if(!INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic())
4545 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
4547 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
4548 INTERP_KERNEL::Node *n(new INTERP_KERNEL::Node(pos[i*SPACEDIM],pos[i*SPACEDIM+1]));
4549 double a(0.),b(0.),c(0.);
4550 a=pol->normalizeMe(b,c); n->applySimilarity(b,c,a);
4551 status=pol->isInOrOut2(n);
4552 delete pol; n->decrRef();
4556 eltsIndexPtr[i+1]++;
4557 elts->pushBackSilent(*iter);
4563 * Finds cells in contact with several balls (i.e. points with precision).
4564 * This method is an extension of getCellContainingPoint() and
4565 * getCellsContainingPoint() for the case of multiple points.
4566 * 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.
4567 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4568 * \param [in] pos - an array of coordinates of points in full interlace mode :
4569 * X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4570 * this->getSpaceDimension() * \a nbOfPoints
4571 * \param [in] nbOfPoints - number of points to locate within \a this mesh.
4572 * \param [in] eps - radius of balls (i.e. the precision).
4573 * \param [out] elts - vector returning ids of found cells.
4574 * \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4575 * dividing cell ids in \a elts into groups each referring to one
4576 * point. Its every element (except the last one) is an index pointing to the
4577 * first id of a group of cells. For example cells in contact with the *i*-th
4578 * point are described by following range of indices:
4579 * [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4580 * \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4581 * Number of cells in contact with the *i*-th point is
4582 * \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4583 * \throw If the coordinates array is not set.
4584 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4586 * \if ENABLE_EXAMPLES
4587 * \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4588 * \ref py_mcumesh_getCellsContainingPoints "Here is a Python example".
4591 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, int nbOfPoints, double eps,
4592 MCAuto<DataArrayInt>& elts, MCAuto<DataArrayInt>& eltsIndex) const
4594 int spaceDim=getSpaceDimension();
4595 int mDim=getMeshDimension();
4600 const double *coords=_coords->getConstPointer();
4601 getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4608 throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4610 else if(spaceDim==2)
4614 const double *coords=_coords->getConstPointer();
4615 getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4618 throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4620 else if(spaceDim==1)
4624 const double *coords=_coords->getConstPointer();
4625 getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4628 throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4631 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4635 * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4636 * least two its edges intersect each other anywhere except their extremities. An
4637 * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4638 * \param [in,out] cells - a vector returning ids of the found cells. It is not
4639 * cleared before filling in.
4640 * \param [in] eps - precision.
4641 * \throw If \a this->getMeshDimension() != 2.
4642 * \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4644 void MEDCouplingUMesh::checkButterflyCells(std::vector<int>& cells, double eps) const
4646 const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4647 if(getMeshDimension()!=2)
4648 throw INTERP_KERNEL::Exception(msg);
4649 int spaceDim=getSpaceDimension();
4650 if(spaceDim!=2 && spaceDim!=3)
4651 throw INTERP_KERNEL::Exception(msg);
4652 const int *conn=_nodal_connec->getConstPointer();
4653 const int *connI=_nodal_connec_index->getConstPointer();
4654 int nbOfCells=getNumberOfCells();
4655 std::vector<double> cell2DinS2;
4656 for(int i=0;i<nbOfCells;i++)
4658 int offset=connI[i];
4659 int nbOfNodesForCell=connI[i+1]-offset-1;
4660 if(nbOfNodesForCell<=3)
4662 bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4663 project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4664 if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4671 * This method is typically requested to unbutterfly 2D linear cells in \b this.
4673 * 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.
4674 * 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.
4676 * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4677 * This convex envelop is computed using Jarvis march algorithm.
4678 * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4679 * 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)
4680 * 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.
4682 * \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.
4683 * \sa MEDCouplingUMesh::colinearize2D
4685 DataArrayInt *MEDCouplingUMesh::convexEnvelop2D()
4687 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4688 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D works only for meshDim=2 and spaceDim=2 !");
4689 checkFullyDefined();
4690 const double *coords=getCoords()->getConstPointer();
4691 int nbOfCells=getNumberOfCells();
4692 MCAuto<DataArrayInt> nodalConnecIndexOut=DataArrayInt::New();
4693 nodalConnecIndexOut->alloc(nbOfCells+1,1);
4694 MCAuto<DataArrayInt> nodalConnecOut(DataArrayInt::New());
4695 int *workIndexOut=nodalConnecIndexOut->getPointer();
4697 const int *nodalConnecIn=_nodal_connec->getConstPointer();
4698 const int *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4699 std::set<INTERP_KERNEL::NormalizedCellType> types;
4700 MCAuto<DataArrayInt> isChanged(DataArrayInt::New());
4701 isChanged->alloc(0,1);
4702 for(int i=0;i<nbOfCells;i++,workIndexOut++)
4704 int pos=nodalConnecOut->getNumberOfTuples();
4705 if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4706 isChanged->pushBackSilent(i);
4707 types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4708 workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4710 if(isChanged->empty())
4712 setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4714 return isChanged.retn();
4718 * This method is \b NOT const because it can modify \a this.
4719 * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4720 * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4721 * \param policy specifies the type of extrusion chosen:
4722 * - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4723 * will be repeated to build each level
4724 * - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4725 * 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
4726 * 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
4728 * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4730 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4732 checkFullyDefined();
4733 mesh1D->checkFullyDefined();
4734 if(!mesh1D->isContiguous1D())
4735 throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4736 if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4737 throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4738 if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4739 throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4740 if(mesh1D->getMeshDimension()!=1)
4741 throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4743 if(isPresenceOfQuadratic())
4745 if(mesh1D->isFullyQuadratic())
4748 throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4750 int oldNbOfNodes(getNumberOfNodes());
4751 MCAuto<DataArrayDouble> newCoords;
4756 newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4761 newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4765 throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4767 setCoords(newCoords);
4768 MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4774 * This method works on a 3D curve linear mesh that is to say (meshDim==1 and spaceDim==3).
4775 * If it is not the case an exception will be thrown.
4776 * This method is non const because the coordinate of \a this can be appended with some new points issued from
4777 * intersection of plane defined by ('origin','vec').
4778 * This method has one in/out parameter : 'cut3DCurve'.
4779 * Param 'cut3DCurve' is expected to be of size 'this->getNumberOfCells()'. For each i in [0,'this->getNumberOfCells()')
4780 * if cut3DCurve[i]==-2, it means that for cell #i in \a this nothing has been detected previously.
4781 * if cut3DCurve[i]==-1, it means that cell#i has been already detected to be fully part of plane defined by ('origin','vec').
4782 * This method will throw an exception if \a this contains a non linear segment.
4784 void MEDCouplingUMesh::split3DCurveWithPlane(const double *origin, const double *vec, double eps, std::vector<int>& cut3DCurve)
4786 checkFullyDefined();
4787 if(getMeshDimension()!=1 || getSpaceDimension()!=3)
4788 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane works on umeshes with meshdim equal to 1 and spaceDim equal to 3 !");
4789 int ncells=getNumberOfCells();
4790 int nnodes=getNumberOfNodes();
4791 double vec2[3],vec3[3],vec4[3];
4792 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
4794 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
4795 vec2[0]=vec[0]/normm; vec2[1]=vec[1]/normm; vec2[2]=vec[2]/normm;
4796 const int *conn=_nodal_connec->getConstPointer();
4797 const int *connI=_nodal_connec_index->getConstPointer();
4798 const double *coo=_coords->getConstPointer();
4799 std::vector<double> addCoo;
4800 for(int i=0;i<ncells;i++)
4802 if(conn[connI[i]]==(int)INTERP_KERNEL::NORM_SEG2)
4804 if(cut3DCurve[i]==-2)
4806 int st=conn[connI[i]+1],endd=conn[connI[i]+2];
4807 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];
4808 double normm2=sqrt(vec3[0]*vec3[0]+vec3[1]*vec3[1]+vec3[2]*vec3[2]);
4809 double colin=std::abs((vec3[0]*vec2[0]+vec3[1]*vec2[1]+vec3[2]*vec2[2])/normm2);
4810 if(colin>eps)//if colin<=eps -> current SEG2 is colinear to the input plane
4812 const double *st2=coo+3*st;
4813 vec4[0]=st2[0]-origin[0]; vec4[1]=st2[1]-origin[1]; vec4[2]=st2[2]-origin[2];
4814 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]));
4815 if(pos>eps && pos<1-eps)
4817 int nNode=((int)addCoo.size())/3;
4818 vec4[0]=st2[0]+pos*vec3[0]; vec4[1]=st2[1]+pos*vec3[1]; vec4[2]=st2[2]+pos*vec3[2];
4819 addCoo.insert(addCoo.end(),vec4,vec4+3);
4820 cut3DCurve[i]=nnodes+nNode;
4826 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane : this method is only available for linear cell (NORM_SEG2) !");
4830 int newNbOfNodes=nnodes+((int)addCoo.size())/3;
4831 MCAuto<DataArrayDouble> coo2=DataArrayDouble::New();
4832 coo2->alloc(newNbOfNodes,3);
4833 double *tmp=coo2->getPointer();
4834 tmp=std::copy(_coords->begin(),_coords->end(),tmp);
4835 std::copy(addCoo.begin(),addCoo.end(),tmp);
4836 DataArrayDouble::SetArrayIn(coo2,_coords);
4841 * This method incarnates the policy 0 for MEDCouplingUMesh::buildExtrudedMesh method.
4842 * \param mesh1D is the input 1D mesh used for translation computation.
4843 * \return newCoords new coords filled by this method.
4845 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslation(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4847 int oldNbOfNodes=getNumberOfNodes();
4848 int nbOf1DCells=mesh1D->getNumberOfCells();
4849 int spaceDim=getSpaceDimension();
4850 DataArrayDouble *ret=DataArrayDouble::New();
4851 std::vector<bool> isQuads;
4852 int nbOfLevsInVec=isQuad?2*nbOf1DCells+1:nbOf1DCells+1;
4853 ret->alloc(oldNbOfNodes*nbOfLevsInVec,spaceDim);
4854 double *retPtr=ret->getPointer();
4855 const double *coords=getCoords()->getConstPointer();
4856 double *work=std::copy(coords,coords+spaceDim*oldNbOfNodes,retPtr);
4858 std::vector<double> c;
4862 for(int i=0;i<nbOf1DCells;i++)
4865 mesh1D->getNodeIdsOfCell(i,v);
4867 mesh1D->getCoordinatesOfNode(v[isQuad?2:1],c);
4868 mesh1D->getCoordinatesOfNode(v[0],c);
4869 std::transform(c.begin(),c.begin()+spaceDim,c.begin()+spaceDim,vec,std::minus<double>());
4870 for(int j=0;j<oldNbOfNodes;j++)
4871 work=std::transform(vec,vec+spaceDim,retPtr+spaceDim*(i*oldNbOfNodes+j),work,std::plus<double>());
4875 mesh1D->getCoordinatesOfNode(v[1],c);
4876 mesh1D->getCoordinatesOfNode(v[0],c);
4877 std::transform(c.begin(),c.begin()+spaceDim,c.begin()+spaceDim,vec,std::minus<double>());
4878 for(int j=0;j<oldNbOfNodes;j++)
4879 work=std::transform(vec,vec+spaceDim,retPtr+spaceDim*(i*oldNbOfNodes+j),work,std::plus<double>());
4882 ret->copyStringInfoFrom(*getCoords());
4887 * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4888 * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4889 * \return newCoords new coords filled by this method.
4891 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4893 if(mesh1D->getSpaceDimension()==2)
4894 return fillExtCoordsUsingTranslAndAutoRotation2D(mesh1D,isQuad);
4895 if(mesh1D->getSpaceDimension()==3)
4896 return fillExtCoordsUsingTranslAndAutoRotation3D(mesh1D,isQuad);
4897 throw INTERP_KERNEL::Exception("Not implemented rotation and translation alg. for spacedim other than 2 and 3 !");
4901 * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4902 * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4903 * \return newCoords new coords filled by this method.
4905 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4908 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D : not implemented for quadratic cells !");
4909 int oldNbOfNodes=getNumberOfNodes();
4910 int nbOf1DCells=mesh1D->getNumberOfCells();
4912 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D : impossible to detect any angle of rotation ! Change extrusion policy 1->0 !");
4913 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
4914 int nbOfLevsInVec=nbOf1DCells+1;
4915 ret->alloc(oldNbOfNodes*nbOfLevsInVec,2);
4916 double *retPtr=ret->getPointer();
4917 retPtr=std::copy(getCoords()->getConstPointer(),getCoords()->getConstPointer()+getCoords()->getNbOfElems(),retPtr);
4918 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
4919 MCAuto<DataArrayDouble> tmp2=getCoords()->deepCopy();
4920 tmp->setCoords(tmp2);
4921 const double *coo1D=mesh1D->getCoords()->getConstPointer();
4922 const int *conn1D=mesh1D->getNodalConnectivity()->getConstPointer();
4923 const int *connI1D=mesh1D->getNodalConnectivityIndex()->getConstPointer();
4924 for(int i=1;i<nbOfLevsInVec;i++)
4926 const double *begin=coo1D+2*conn1D[connI1D[i-1]+1];
4927 const double *end=coo1D+2*conn1D[connI1D[i-1]+2];
4928 const double *third=i+1<nbOfLevsInVec?coo1D+2*conn1D[connI1D[i]+2]:coo1D+2*conn1D[connI1D[i-2]+1];
4929 const double vec[2]={end[0]-begin[0],end[1]-begin[1]};
4930 tmp->translate(vec);
4931 double tmp3[2],radius,alpha,alpha0;
4932 const double *p0=i+1<nbOfLevsInVec?begin:third;
4933 const double *p1=i+1<nbOfLevsInVec?end:begin;
4934 const double *p2=i+1<nbOfLevsInVec?third:end;
4935 INTERP_KERNEL::EdgeArcCircle::GetArcOfCirclePassingThru(p0,p1,p2,tmp3,radius,alpha,alpha0);
4936 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]);
4937 double angle=acos(cosangle/(radius*radius));
4938 tmp->rotate(end,0,angle);
4939 retPtr=std::copy(tmp2->getConstPointer(),tmp2->getConstPointer()+tmp2->getNbOfElems(),retPtr);
4945 * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4946 * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4947 * \return newCoords new coords filled by this method.
4949 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4952 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D : not implemented for quadratic cells !");
4953 int oldNbOfNodes=getNumberOfNodes();
4954 int nbOf1DCells=mesh1D->getNumberOfCells();
4956 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D : impossible to detect any angle of rotation ! Change extrusion policy 1->0 !");
4957 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
4958 int nbOfLevsInVec=nbOf1DCells+1;
4959 ret->alloc(oldNbOfNodes*nbOfLevsInVec,3);
4960 double *retPtr=ret->getPointer();
4961 retPtr=std::copy(getCoords()->getConstPointer(),getCoords()->getConstPointer()+getCoords()->getNbOfElems(),retPtr);
4962 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
4963 MCAuto<DataArrayDouble> tmp2=getCoords()->deepCopy();
4964 tmp->setCoords(tmp2);
4965 const double *coo1D=mesh1D->getCoords()->getConstPointer();
4966 const int *conn1D=mesh1D->getNodalConnectivity()->getConstPointer();
4967 const int *connI1D=mesh1D->getNodalConnectivityIndex()->getConstPointer();
4968 for(int i=1;i<nbOfLevsInVec;i++)
4970 const double *begin=coo1D+3*conn1D[connI1D[i-1]+1];
4971 const double *end=coo1D+3*conn1D[connI1D[i-1]+2];
4972 const double *third=i+1<nbOfLevsInVec?coo1D+3*conn1D[connI1D[i]+2]:coo1D+3*conn1D[connI1D[i-2]+1];
4973 const double vec[3]={end[0]-begin[0],end[1]-begin[1],end[2]-begin[2]};
4974 tmp->translate(vec);
4975 double tmp3[2],radius,alpha,alpha0;
4976 const double *p0=i+1<nbOfLevsInVec?begin:third;
4977 const double *p1=i+1<nbOfLevsInVec?end:begin;
4978 const double *p2=i+1<nbOfLevsInVec?third:end;
4979 double vecPlane[3]={
4980 (p1[1]-p0[1])*(p2[2]-p1[2])-(p1[2]-p0[2])*(p2[1]-p1[1]),
4981 (p1[2]-p0[2])*(p2[0]-p1[0])-(p1[0]-p0[0])*(p2[2]-p1[2]),
4982 (p1[0]-p0[0])*(p2[1]-p1[1])-(p1[1]-p0[1])*(p2[0]-p1[0]),
4984 double norm=sqrt(vecPlane[0]*vecPlane[0]+vecPlane[1]*vecPlane[1]+vecPlane[2]*vecPlane[2]);
4987 vecPlane[0]/=norm; vecPlane[1]/=norm; vecPlane[2]/=norm;
4988 double norm2=sqrt(vecPlane[0]*vecPlane[0]+vecPlane[1]*vecPlane[1]);
4989 double vec2[2]={vecPlane[1]/norm2,-vecPlane[0]/norm2};
4991 double c2=cos(asin(s2));
4993 {vec2[0]*vec2[0]*(1-c2)+c2, vec2[0]*vec2[1]*(1-c2), vec2[1]*s2},
4994 {vec2[0]*vec2[1]*(1-c2), vec2[1]*vec2[1]*(1-c2)+c2, -vec2[0]*s2},
4995 {-vec2[1]*s2, vec2[0]*s2, c2}
4997 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]};
4998 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]};
4999 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]};
5000 INTERP_KERNEL::EdgeArcCircle::GetArcOfCirclePassingThru(p0r,p1r,p2r,tmp3,radius,alpha,alpha0);
5001 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]);
5002 double angle=acos(cosangle/(radius*radius));
5003 tmp->rotate(end,vecPlane,angle);
5005 retPtr=std::copy(tmp2->getConstPointer(),tmp2->getConstPointer()+tmp2->getNbOfElems(),retPtr);
5011 * This method is private because not easy to use for end user. This method is const contrary to
5012 * MEDCouplingUMesh::buildExtrudedMesh method because this->_coords are expected to contain
5013 * the coords sorted slice by slice.
5014 * \param isQuad specifies presence of quadratic cells.
5016 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMeshFromThisLowLev(int nbOfNodesOf1Lev, bool isQuad) const
5018 int nbOf1DCells(getNumberOfNodes()/nbOfNodesOf1Lev-1);
5019 int nbOf2DCells(getNumberOfCells());
5020 int nbOf3DCells(nbOf2DCells*nbOf1DCells);
5021 MEDCouplingUMesh *ret(MEDCouplingUMesh::New("Extruded",getMeshDimension()+1));
5022 const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5023 MCAuto<DataArrayInt> newConn(DataArrayInt::New()),newConnI(DataArrayInt::New());
5024 newConnI->alloc(nbOf3DCells+1,1);
5025 int *newConnIPtr(newConnI->getPointer());
5027 std::vector<int> newc;
5028 for(int j=0;j<nbOf2DCells;j++)
5030 AppendExtrudedCell(conn+connI[j],conn+connI[j+1],nbOfNodesOf1Lev,isQuad,newc);
5031 *newConnIPtr++=(int)newc.size();
5033 newConn->alloc((int)(newc.size())*nbOf1DCells,1);
5034 int *newConnPtr(newConn->getPointer());
5035 int deltaPerLev(isQuad?2*nbOfNodesOf1Lev:nbOfNodesOf1Lev);
5036 newConnIPtr=newConnI->getPointer();
5037 for(int iz=0;iz<nbOf1DCells;iz++)
5040 std::transform(newConnIPtr+1,newConnIPtr+1+nbOf2DCells,newConnIPtr+1+iz*nbOf2DCells,std::bind2nd(std::plus<int>(),newConnIPtr[iz*nbOf2DCells]));
5041 const int *posOfTypeOfCell(newConnIPtr);
5042 for(std::vector<int>::const_iterator iter=newc.begin();iter!=newc.end();iter++,newConnPtr++)
5044 int icell((int)(iter-newc.begin()));//std::distance unfortunately cannot been called here in C++98
5045 if(icell!=*posOfTypeOfCell)
5048 *newConnPtr=(*iter)+iz*deltaPerLev;
5059 ret->setConnectivity(newConn,newConnI,true);
5060 ret->setCoords(getCoords());
5065 * Checks if \a this mesh is constituted by only quadratic cells.
5066 * \return bool - \c true if there are only quadratic cells in \a this mesh.
5067 * \throw If the coordinates array is not set.
5068 * \throw If the nodal connectivity of cells is not defined.
5070 bool MEDCouplingUMesh::isFullyQuadratic() const
5072 checkFullyDefined();
5074 int nbOfCells=getNumberOfCells();
5075 for(int i=0;i<nbOfCells && ret;i++)
5077 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5078 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5079 ret=cm.isQuadratic();
5085 * Checks if \a this mesh includes any quadratic cell.
5086 * \return bool - \c true if there is at least one quadratic cells in \a this mesh.
5087 * \throw If the coordinates array is not set.
5088 * \throw If the nodal connectivity of cells is not defined.
5090 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
5092 checkFullyDefined();
5094 int nbOfCells=getNumberOfCells();
5095 for(int i=0;i<nbOfCells && !ret;i++)
5097 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5098 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5099 ret=cm.isQuadratic();
5105 * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
5106 * this mesh, it remains unchanged.
5107 * \throw If the coordinates array is not set.
5108 * \throw If the nodal connectivity of cells is not defined.
5110 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
5112 checkFullyDefined();
5113 int nbOfCells=getNumberOfCells();
5115 const int *iciptr=_nodal_connec_index->getConstPointer();
5116 for(int i=0;i<nbOfCells;i++)
5118 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5119 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5120 if(cm.isQuadratic())
5122 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
5123 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
5124 if(!cml.isDynamic())
5125 delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
5127 delta+=(iciptr[i+1]-iciptr[i]-1)/2;
5132 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5133 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5134 const int *icptr=_nodal_connec->getConstPointer();
5135 newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
5136 newConnI->alloc(nbOfCells+1,1);
5137 int *ocptr=newConn->getPointer();
5138 int *ociptr=newConnI->getPointer();
5141 for(int i=0;i<nbOfCells;i++,ociptr++)
5143 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
5144 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5145 if(!cm.isQuadratic())
5147 _types.insert(type);
5148 ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
5149 ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
5153 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
5154 _types.insert(typel);
5155 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
5156 int newNbOfNodes=cml.getNumberOfNodes();
5158 newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
5159 *ocptr++=(int)typel;
5160 ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
5161 ociptr[1]=ociptr[0]+newNbOfNodes+1;
5164 setConnectivity(newConn,newConnI,false);
5168 * This method converts all linear cell in \a this to quadratic one.
5169 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
5170 * 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)
5171 * 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.
5172 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
5173 * end of the existing coordinates.
5175 * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
5176 * corresponding quadratic cells. 1 is those creating the 'most' complex.
5177 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5179 * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
5181 * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
5183 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
5185 DataArrayInt *conn=0,*connI=0;
5186 DataArrayDouble *coords=0;
5187 std::set<INTERP_KERNEL::NormalizedCellType> types;
5188 checkFullyDefined();
5189 MCAuto<DataArrayInt> ret,connSafe,connISafe;
5190 MCAuto<DataArrayDouble> coordsSafe;
5191 int meshDim=getMeshDimension();
5192 switch(conversionType)
5198 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
5199 connSafe=conn; connISafe=connI; coordsSafe=coords;
5202 ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
5203 connSafe=conn; connISafe=connI; coordsSafe=coords;
5206 ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
5207 connSafe=conn; connISafe=connI; coordsSafe=coords;
5210 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
5218 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
5219 connSafe=conn; connISafe=connI; coordsSafe=coords;
5222 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
5223 connSafe=conn; connISafe=connI; coordsSafe=coords;
5226 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
5227 connSafe=conn; connISafe=connI; coordsSafe=coords;
5230 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
5235 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
5237 setConnectivity(connSafe,connISafe,false);
5239 setCoords(coordsSafe);
5244 * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
5245 * so that the number of cells remains the same. Quadratic faces are converted to
5246 * polygons. This method works only for 2D meshes in
5247 * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
5248 * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
5249 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5250 * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
5251 * a polylinized edge constituting the input polygon.
5252 * \throw If the coordinates array is not set.
5253 * \throw If the nodal connectivity of cells is not defined.
5254 * \throw If \a this->getMeshDimension() != 2.
5255 * \throw If \a this->getSpaceDimension() != 2.
5257 void MEDCouplingUMesh::tessellate2D(double eps)
5259 int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
5261 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
5265 return tessellate2DCurveInternal(eps);
5267 return tessellate2DInternal(eps);
5269 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
5273 * Tessellates \a this 1D mesh in 2D space by dividing not straight quadratic edges.
5274 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5275 * \param [in] eps - specifies the maximal angle (in radian) between 2 sub-edges of
5276 * a sub-divided edge.
5277 * \throw If the coordinates array is not set.
5278 * \throw If the nodal connectivity of cells is not defined.
5279 * \throw If \a this->getMeshDimension() != 1.
5280 * \throw If \a this->getSpaceDimension() != 2.
5285 * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
5286 * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
5287 * The nodes to be added in those 2D cells are defined by the pair of \a nodeIdsToAdd and \a nodeIdsIndexToAdd.
5288 * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
5289 * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
5290 * This method can be seen as the opposite method of colinearize2D.
5291 * 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
5292 * to avoid to modify the numbering of existing nodes.
5294 * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
5295 * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
5296 * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
5297 * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
5298 * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
5299 * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
5300 * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
5302 * \sa buildDescendingConnectivity2
5304 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayInt *nodeIdsToAdd, const DataArrayInt *nodeIdsIndexToAdd, const DataArrayInt *edgeIdsToBeSplit,
5305 const MEDCouplingUMesh *mesh1Desc, const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *revDesc, const DataArrayInt *revDescI)
5307 if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
5308 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
5309 nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
5310 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
5311 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
5312 if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
5313 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
5314 //DataArrayInt *out0(0),*outi0(0);
5315 //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
5316 //MCAuto<DataArrayInt> out0s(out0),outi0s(outi0);
5317 //out0s=out0s->buildUnique(); out0s->sort(true);
5322 * Implementes \a conversionType 0 for meshes with meshDim = 1, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5323 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5324 * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5326 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic1D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5328 MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5329 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5330 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5331 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5332 int nbOfCells=getNumberOfCells();
5333 int nbOfNodes=getNumberOfNodes();
5334 const int *cPtr=_nodal_connec->getConstPointer();
5335 const int *icPtr=_nodal_connec_index->getConstPointer();
5336 int lastVal=0,offset=nbOfNodes;
5337 for(int i=0;i<nbOfCells;i++,icPtr++)
5339 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5340 if(type==INTERP_KERNEL::NORM_SEG2)
5342 types.insert(INTERP_KERNEL::NORM_SEG3);
5343 newConn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG3);
5344 newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[0]+3);
5345 newConn->pushBackSilent(offset++);
5347 newConnI->pushBackSilent(lastVal);
5348 ret->pushBackSilent(i);
5353 lastVal+=(icPtr[1]-icPtr[0]);
5354 newConnI->pushBackSilent(lastVal);
5355 newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5358 MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5359 coords=DataArrayDouble::Aggregate(getCoords(),tmp); conn=newConn.retn(); connI=newConnI.retn();
5363 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
5365 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5366 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5367 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5369 const int *descPtr(desc->begin()),*descIPtr(descI->begin());
5370 DataArrayInt *conn1D=0,*conn1DI=0;
5371 std::set<INTERP_KERNEL::NormalizedCellType> types1D;
5372 DataArrayDouble *coordsTmp=0;
5373 MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=0;
5374 MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5375 MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5376 const int *c1DPtr=conn1D->begin();
5377 const int *c1DIPtr=conn1DI->begin();
5378 int nbOfCells=getNumberOfCells();
5379 const int *cPtr=_nodal_connec->getConstPointer();
5380 const int *icPtr=_nodal_connec_index->getConstPointer();
5382 for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++)
5384 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5385 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5386 if(!cm.isQuadratic())
5388 INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType();
5389 types.insert(typ2); newConn->pushBackSilent(typ2);
5390 newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5391 for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5392 newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5393 lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0]);
5394 newConnI->pushBackSilent(lastVal);
5395 ret->pushBackSilent(i);
5400 lastVal+=(icPtr[1]-icPtr[0]);
5401 newConnI->pushBackSilent(lastVal);
5402 newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5405 conn=newConn.retn(); connI=newConnI.retn(); coords=coordsTmpSafe.retn();
5410 * Implementes \a conversionType 0 for meshes with meshDim = 2, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5411 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5412 * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5414 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic2D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5416 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5417 MCAuto<MEDCouplingUMesh> m1D=buildDescendingConnectivity(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5418 return convertLinearCellsToQuadratic2DAnd3D0(m1D,desc,descI,conn,connI,coords,types);
5421 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic2D1(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5423 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5424 MCAuto<MEDCouplingUMesh> m1D=buildDescendingConnectivity(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5426 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5427 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5428 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5430 MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5431 const int *descPtr(desc->begin()),*descIPtr(descI->begin());
5432 DataArrayInt *conn1D=0,*conn1DI=0;
5433 std::set<INTERP_KERNEL::NormalizedCellType> types1D;
5434 DataArrayDouble *coordsTmp=0;
5435 MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=0;
5436 MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5437 MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5438 const int *c1DPtr=conn1D->begin();
5439 const int *c1DIPtr=conn1DI->begin();
5440 int nbOfCells=getNumberOfCells();
5441 const int *cPtr=_nodal_connec->getConstPointer();
5442 const int *icPtr=_nodal_connec_index->getConstPointer();
5443 int lastVal=0,offset=coordsTmpSafe->getNumberOfTuples();
5444 for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++)
5446 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5447 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5448 if(!cm.isQuadratic())
5450 INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType2();
5451 types.insert(typ2); newConn->pushBackSilent(typ2);
5452 newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5453 for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5454 newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5455 newConn->pushBackSilent(offset+ret->getNumberOfTuples());
5456 lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0])+1;
5457 newConnI->pushBackSilent(lastVal);
5458 ret->pushBackSilent(i);
5463 lastVal+=(icPtr[1]-icPtr[0]);
5464 newConnI->pushBackSilent(lastVal);
5465 newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5468 MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5469 coords=DataArrayDouble::Aggregate(coordsTmpSafe,tmp); conn=newConn.retn(); connI=newConnI.retn();
5474 * Implementes \a conversionType 0 for meshes with meshDim = 3, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5475 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5476 * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5478 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic3D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5480 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5481 MCAuto<MEDCouplingUMesh> m1D=explode3DMeshTo1D(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5482 return convertLinearCellsToQuadratic2DAnd3D0(m1D,desc,descI,conn,connI,coords,types);
5485 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic3D1(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5487 MCAuto<DataArrayInt> desc2(DataArrayInt::New()),desc2I(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5488 MCAuto<MEDCouplingUMesh> m2D=buildDescendingConnectivityGen<MinusOneSonsGeneratorBiQuadratic>(desc2,desc2I,tmp2,tmp3,MEDCouplingFastNbrer); tmp2=0; tmp3=0;
5489 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),desc1I(DataArrayInt::New()),tmp4(DataArrayInt::New()),tmp5(DataArrayInt::New());
5490 MCAuto<MEDCouplingUMesh> m1D=explode3DMeshTo1D(desc1,desc1I,tmp4,tmp5); tmp4=0; tmp5=0;
5492 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5493 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5494 MCAuto<DataArrayInt> ret=DataArrayInt::New(),ret2=DataArrayInt::New(); ret->alloc(0,1); ret2->alloc(0,1);
5496 MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5497 const int *descPtr(desc1->begin()),*descIPtr(desc1I->begin()),*desc2Ptr(desc2->begin()),*desc2IPtr(desc2I->begin());
5498 DataArrayInt *conn1D=0,*conn1DI=0,*conn2D=0,*conn2DI=0;
5499 std::set<INTERP_KERNEL::NormalizedCellType> types1D,types2D;
5500 DataArrayDouble *coordsTmp=0,*coordsTmp2=0;
5501 MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=DataArrayInt::New(); ret1D->alloc(0,1);
5502 MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5503 MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5504 MCAuto<DataArrayInt> ret2D=m2D->convertLinearCellsToQuadratic2D1(conn2D,conn2DI,coordsTmp2,types2D); ret2D=DataArrayInt::New(); ret2D->alloc(0,1);
5505 MCAuto<DataArrayDouble> coordsTmp2Safe(coordsTmp2);
5506 MCAuto<DataArrayInt> conn2DSafe(conn2D),conn2DISafe(conn2DI);
5507 const int *c1DPtr=conn1D->begin(),*c1DIPtr=conn1DI->begin(),*c2DPtr=conn2D->begin(),*c2DIPtr=conn2DI->begin();
5508 int nbOfCells=getNumberOfCells();
5509 const int *cPtr=_nodal_connec->getConstPointer();
5510 const int *icPtr=_nodal_connec_index->getConstPointer();
5511 int lastVal=0,offset=coordsTmpSafe->getNumberOfTuples();
5512 for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++,desc2IPtr++)
5514 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5515 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5516 if(!cm.isQuadratic())
5518 INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType2();
5519 if(typ2==INTERP_KERNEL::NORM_ERROR)
5521 std::ostringstream oss; oss << "MEDCouplingUMesh::convertLinearCellsToQuadratic3D1 : On cell #" << i << " the linear cell type does not support advanced quadratization !";
5522 throw INTERP_KERNEL::Exception(oss.str());
5524 types.insert(typ2); newConn->pushBackSilent(typ2);
5525 newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5526 for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5527 newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5528 for(const int *d=desc2Ptr+desc2IPtr[0];d!=desc2Ptr+desc2IPtr[1];d++)
5530 int nodeId2=c2DPtr[c2DIPtr[(*d)+1]-1];
5531 int tmpPos=newConn->getNumberOfTuples();
5532 newConn->pushBackSilent(nodeId2);
5533 ret2D->pushBackSilent(nodeId2); ret1D->pushBackSilent(tmpPos);
5535 newConn->pushBackSilent(offset+ret->getNumberOfTuples());
5536 lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0])+(desc2IPtr[1]-desc2IPtr[0])+1;
5537 newConnI->pushBackSilent(lastVal);
5538 ret->pushBackSilent(i);
5543 lastVal+=(icPtr[1]-icPtr[0]);
5544 newConnI->pushBackSilent(lastVal);
5545 newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5548 MCAuto<DataArrayInt> diffRet2D=ret2D->getDifferentValues();
5549 MCAuto<DataArrayInt> o2nRet2D=diffRet2D->invertArrayN2O2O2N(coordsTmp2Safe->getNumberOfTuples());
5550 coordsTmp2Safe=coordsTmp2Safe->selectByTupleId(diffRet2D->begin(),diffRet2D->end());
5551 MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5552 std::vector<const DataArrayDouble *> v(3); v[0]=coordsTmpSafe; v[1]=coordsTmp2Safe; v[2]=tmp;
5553 int *c=newConn->getPointer();
5554 const int *cI(newConnI->begin());
5555 for(const int *elt=ret1D->begin();elt!=ret1D->end();elt++)
5556 c[*elt]=o2nRet2D->getIJ(c[*elt],0)+offset;
5557 offset=coordsTmp2Safe->getNumberOfTuples();
5558 for(const int *elt=ret->begin();elt!=ret->end();elt++)
5559 c[cI[(*elt)+1]-1]+=offset;
5560 coords=DataArrayDouble::Aggregate(v); conn=newConn.retn(); connI=newConnI.retn();
5565 * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
5566 * In addition, returns an array mapping new cells to old ones. <br>
5567 * This method typically increases the number of cells in \a this mesh
5568 * but the number of nodes remains \b unchanged.
5569 * That's why the 3D splitting policies
5570 * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
5571 * \param [in] policy - specifies a pattern used for splitting.
5572 * The semantic of \a policy is:
5573 * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
5574 * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
5575 * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8 into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
5576 * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8 into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
5579 * \return DataArrayInt * - a new instance of DataArrayInt holding, for each new cell,
5580 * an id of old cell producing it. The caller is to delete this array using
5581 * decrRef() as it is no more needed.
5583 * \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
5584 * \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
5585 * and \a this->getMeshDimension() != 3.
5586 * \throw If \a policy is not one of the four discussed above.
5587 * \throw If the nodal connectivity of cells is not defined.
5588 * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
5590 DataArrayInt *MEDCouplingUMesh::simplexize(int policy)
5595 return simplexizePol0();
5597 return simplexizePol1();
5598 case (int) INTERP_KERNEL::PLANAR_FACE_5:
5599 return simplexizePlanarFace5();
5600 case (int) INTERP_KERNEL::PLANAR_FACE_6:
5601 return simplexizePlanarFace6();
5603 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)");
5608 * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
5609 * - 1D: INTERP_KERNEL::NORM_SEG2
5610 * - 2D: INTERP_KERNEL::NORM_TRI3
5611 * - 3D: INTERP_KERNEL::NORM_TETRA4.
5613 * This method is useful for users that need to use P1 field services as
5614 * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
5615 * All these methods need mesh support containing only simplex cells.
5616 * \return bool - \c true if there are only simplex cells in \a this mesh.
5617 * \throw If the coordinates array is not set.
5618 * \throw If the nodal connectivity of cells is not defined.
5619 * \throw If \a this->getMeshDimension() < 1.
5621 bool MEDCouplingUMesh::areOnlySimplexCells() const
5623 checkFullyDefined();
5624 int mdim=getMeshDimension();
5625 if(mdim<1 || mdim>3)
5626 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
5627 int nbCells=getNumberOfCells();
5628 const int *conn=_nodal_connec->getConstPointer();
5629 const int *connI=_nodal_connec_index->getConstPointer();
5630 for(int i=0;i<nbCells;i++)
5632 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5640 * This method implements policy 0 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5642 DataArrayInt *MEDCouplingUMesh::simplexizePol0()
5644 checkConnectivityFullyDefined();
5645 if(getMeshDimension()!=2)
5646 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePol0 : this policy is only available for mesh with meshdim == 2 !");
5647 int nbOfCells=getNumberOfCells();
5648 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5649 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_QUAD4);
5650 ret->alloc(nbOfCells+nbOfCutCells,1);
5651 if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5652 int *retPt=ret->getPointer();
5653 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5654 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5655 newConnI->alloc(nbOfCells+nbOfCutCells+1,1);
5656 newConn->alloc(getNodalConnectivityArrayLen()+3*nbOfCutCells,1);
5657 int *pt=newConn->getPointer();
5658 int *ptI=newConnI->getPointer();
5660 const int *oldc=_nodal_connec->getConstPointer();
5661 const int *ci=_nodal_connec_index->getConstPointer();
5662 for(int i=0;i<nbOfCells;i++,ci++)
5664 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_QUAD4)
5666 const int tmp[8]={(int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+2],oldc[ci[0]+3],
5667 (int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+3],oldc[ci[0]+4]};
5668 pt=std::copy(tmp,tmp+8,pt);
5677 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5678 ptI[1]=ptI[0]+ci[1]-ci[0];
5683 _nodal_connec->decrRef();
5684 _nodal_connec=newConn.retn();
5685 _nodal_connec_index->decrRef();
5686 _nodal_connec_index=newConnI.retn();
5693 * This method implements policy 1 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5695 DataArrayInt *MEDCouplingUMesh::simplexizePol1()
5697 checkConnectivityFullyDefined();
5698 if(getMeshDimension()!=2)
5699 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePol0 : this policy is only available for mesh with meshdim == 2 !");
5700 int nbOfCells=getNumberOfCells();
5701 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5702 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_QUAD4);
5703 ret->alloc(nbOfCells+nbOfCutCells,1);
5704 if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5705 int *retPt=ret->getPointer();
5706 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5707 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5708 newConnI->alloc(nbOfCells+nbOfCutCells+1,1);
5709 newConn->alloc(getNodalConnectivityArrayLen()+3*nbOfCutCells,1);
5710 int *pt=newConn->getPointer();
5711 int *ptI=newConnI->getPointer();
5713 const int *oldc=_nodal_connec->getConstPointer();
5714 const int *ci=_nodal_connec_index->getConstPointer();
5715 for(int i=0;i<nbOfCells;i++,ci++)
5717 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_QUAD4)
5719 const int tmp[8]={(int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+2],oldc[ci[0]+4],
5720 (int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+2],oldc[ci[0]+3],oldc[ci[0]+4]};
5721 pt=std::copy(tmp,tmp+8,pt);
5730 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5731 ptI[1]=ptI[0]+ci[1]-ci[0];
5736 _nodal_connec->decrRef();
5737 _nodal_connec=newConn.retn();
5738 _nodal_connec_index->decrRef();
5739 _nodal_connec_index=newConnI.retn();
5746 * This method implements policy INTERP_KERNEL::PLANAR_FACE_5 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5748 DataArrayInt *MEDCouplingUMesh::simplexizePlanarFace5()
5750 checkConnectivityFullyDefined();
5751 if(getMeshDimension()!=3)
5752 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePlanarFace5 : this policy is only available for mesh with meshdim == 3 !");
5753 int nbOfCells=getNumberOfCells();
5754 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5755 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_HEXA8);
5756 ret->alloc(nbOfCells+4*nbOfCutCells,1);
5757 if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5758 int *retPt=ret->getPointer();
5759 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5760 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5761 newConnI->alloc(nbOfCells+4*nbOfCutCells+1,1);
5762 newConn->alloc(getNodalConnectivityArrayLen()+16*nbOfCutCells,1);//21
5763 int *pt=newConn->getPointer();
5764 int *ptI=newConnI->getPointer();
5766 const int *oldc=_nodal_connec->getConstPointer();
5767 const int *ci=_nodal_connec_index->getConstPointer();
5768 for(int i=0;i<nbOfCells;i++,ci++)
5770 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_HEXA8)
5772 for(int j=0;j<5;j++,pt+=5,ptI++)
5774 pt[0]=(int)INTERP_KERNEL::NORM_TETRA4;
5775 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];
5782 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5783 ptI[1]=ptI[0]+ci[1]-ci[0];
5788 _nodal_connec->decrRef();
5789 _nodal_connec=newConn.retn();
5790 _nodal_connec_index->decrRef();
5791 _nodal_connec_index=newConnI.retn();
5798 * This method implements policy INTERP_KERNEL::PLANAR_FACE_6 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5800 DataArrayInt *MEDCouplingUMesh::simplexizePlanarFace6()
5802 checkConnectivityFullyDefined();
5803 if(getMeshDimension()!=3)
5804 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePlanarFace6 : this policy is only available for mesh with meshdim == 3 !");
5805 int nbOfCells=getNumberOfCells();
5806 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5807 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_HEXA8);
5808 ret->alloc(nbOfCells+5*nbOfCutCells,1);
5809 if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5810 int *retPt=ret->getPointer();
5811 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5812 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5813 newConnI->alloc(nbOfCells+5*nbOfCutCells+1,1);
5814 newConn->alloc(getNodalConnectivityArrayLen()+21*nbOfCutCells,1);
5815 int *pt=newConn->getPointer();
5816 int *ptI=newConnI->getPointer();
5818 const int *oldc=_nodal_connec->getConstPointer();
5819 const int *ci=_nodal_connec_index->getConstPointer();
5820 for(int i=0;i<nbOfCells;i++,ci++)
5822 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_HEXA8)
5824 for(int j=0;j<6;j++,pt+=5,ptI++)
5826 pt[0]=(int)INTERP_KERNEL::NORM_TETRA4;
5827 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];
5834 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5835 ptI[1]=ptI[0]+ci[1]-ci[0];
5840 _nodal_connec->decrRef();
5841 _nodal_connec=newConn.retn();
5842 _nodal_connec_index->decrRef();
5843 _nodal_connec_index=newConnI.retn();
5850 * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
5851 * so that the number of cells remains the same. Quadratic faces are converted to
5852 * polygons. This method works only for 2D meshes in
5853 * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
5854 * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
5855 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5856 * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
5857 * a polylinized edge constituting the input polygon.
5858 * \throw If the coordinates array is not set.
5859 * \throw If the nodal connectivity of cells is not defined.
5860 * \throw If \a this->getMeshDimension() != 2.
5861 * \throw If \a this->getSpaceDimension() != 2.
5863 void MEDCouplingUMesh::tessellate2DInternal(double eps)
5865 checkFullyDefined();
5866 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
5867 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DInternal works on umeshes with meshdim equal to 2 and spaceDim equal to 2 too!");
5868 double epsa=fabs(eps);
5869 if(epsa<std::numeric_limits<double>::min())
5870 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 !");
5871 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
5872 MCAuto<MEDCouplingUMesh> mDesc(buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1));
5873 revDesc1=0; revDescIndx1=0;
5874 mDesc->tessellate2D(eps);
5875 subDivide2DMesh(mDesc->_nodal_connec->getConstPointer(),mDesc->_nodal_connec_index->getConstPointer(),desc1->getConstPointer(),descIndx1->getConstPointer());
5876 setCoords(mDesc->getCoords());
5880 * Tessellates \a this 1D mesh in 2D space by dividing not straight quadratic edges.
5881 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5882 * \param [in] eps - specifies the maximal angle (in radian) between 2 sub-edges of
5883 * a sub-divided edge.
5884 * \throw If the coordinates array is not set.
5885 * \throw If the nodal connectivity of cells is not defined.
5886 * \throw If \a this->getMeshDimension() != 1.
5887 * \throw If \a this->getSpaceDimension() != 2.
5889 void MEDCouplingUMesh::tessellate2DCurveInternal(double eps)
5891 checkFullyDefined();
5892 if(getMeshDimension()!=1 || getSpaceDimension()!=2)
5893 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DCurveInternal works on umeshes with meshdim equal to 1 and spaceDim equal to 2 too!");
5894 double epsa=fabs(eps);
5895 if(epsa<std::numeric_limits<double>::min())
5896 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 !");
5897 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=1.e-10;
5898 int nbCells=getNumberOfCells();
5899 int nbNodes=getNumberOfNodes();
5900 const int *conn=_nodal_connec->getConstPointer();
5901 const int *connI=_nodal_connec_index->getConstPointer();
5902 const double *coords=_coords->getConstPointer();
5903 std::vector<double> addCoo;
5904 std::vector<int> newConn;//no direct DataArrayInt because interface with Geometric2D
5905 MCAuto<DataArrayInt> newConnI(DataArrayInt::New());
5906 newConnI->alloc(nbCells+1,1);
5907 int *newConnIPtr=newConnI->getPointer();
5910 INTERP_KERNEL::Node *tmp2[3];
5911 std::set<INTERP_KERNEL::NormalizedCellType> types;
5912 for(int i=0;i<nbCells;i++,newConnIPtr++)
5914 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5915 if(cm.isQuadratic())
5916 {//assert(connI[i+1]-connI[i]-1==3)
5917 tmp1[0]=conn[connI[i]+1+0]; tmp1[1]=conn[connI[i]+1+1]; tmp1[2]=conn[connI[i]+1+2];
5918 tmp2[0]=new INTERP_KERNEL::Node(coords[2*tmp1[0]],coords[2*tmp1[0]+1]);
5919 tmp2[1]=new INTERP_KERNEL::Node(coords[2*tmp1[1]],coords[2*tmp1[1]+1]);
5920 tmp2[2]=new INTERP_KERNEL::Node(coords[2*tmp1[2]],coords[2*tmp1[2]+1]);
5921 INTERP_KERNEL::EdgeArcCircle *eac=INTERP_KERNEL::EdgeArcCircle::BuildFromNodes(tmp2[0],tmp2[2],tmp2[1]);
5924 eac->tesselate(tmp1,nbNodes,epsa,newConn,addCoo);
5925 types.insert((INTERP_KERNEL::NormalizedCellType)newConn[newConnIPtr[0]]);
5927 newConnIPtr[1]=(int)newConn.size();
5931 types.insert(INTERP_KERNEL::NORM_SEG2);
5932 newConn.push_back(INTERP_KERNEL::NORM_SEG2);
5933 newConn.insert(newConn.end(),conn+connI[i]+1,conn+connI[i]+3);
5934 newConnIPtr[1]=newConnIPtr[0]+3;
5939 types.insert((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5940 newConn.insert(newConn.end(),conn+connI[i],conn+connI[i+1]);
5941 newConnIPtr[1]=newConnIPtr[0]+3;
5944 if(addCoo.empty() && ((int)newConn.size())==_nodal_connec->getNumberOfTuples())//nothing happens during tessellation : no update needed
5947 DataArrayInt::SetArrayIn(newConnI,_nodal_connec_index);
5948 MCAuto<DataArrayInt> newConnArr=DataArrayInt::New();
5949 newConnArr->alloc((int)newConn.size(),1);
5950 std::copy(newConn.begin(),newConn.end(),newConnArr->getPointer());
5951 DataArrayInt::SetArrayIn(newConnArr,_nodal_connec);
5952 MCAuto<DataArrayDouble> newCoords=DataArrayDouble::New();
5953 newCoords->alloc(nbNodes+((int)addCoo.size())/2,2);
5954 double *work=std::copy(_coords->begin(),_coords->end(),newCoords->getPointer());
5955 std::copy(addCoo.begin(),addCoo.end(),work);
5956 DataArrayDouble::SetArrayIn(newCoords,_coords);
5961 * 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.
5962 * This method completly ignore coordinates.
5963 * \param nodeSubdived is the nodal connectivity of subdivision of edges
5964 * \param nodeIndxSubdived is the nodal connectivity index of subdivision of edges
5965 * \param desc is descending connectivity in format specified in MEDCouplingUMesh::buildDescendingConnectivity2
5966 * \param descIndex is descending connectivity index in format specified in MEDCouplingUMesh::buildDescendingConnectivity2
5968 void MEDCouplingUMesh::subDivide2DMesh(const int *nodeSubdived, const int *nodeIndxSubdived, const int *desc, const int *descIndex)
5970 checkFullyDefined();
5971 if(getMeshDimension()!=2)
5972 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::subDivide2DMesh : works only on umesh with meshdim==2 !");
5973 int nbOfCells=getNumberOfCells();
5974 int *connI=_nodal_connec_index->getPointer();
5976 for(int i=0;i<nbOfCells;i++,connI++)
5978 int offset=descIndex[i];
5979 int nbOfEdges=descIndex[i+1]-offset;
5981 bool ddirect=desc[offset+nbOfEdges-1]>0;
5982 int eedgeId=std::abs(desc[offset+nbOfEdges-1])-1;
5983 int ref=ddirect?nodeSubdived[nodeIndxSubdived[eedgeId+1]-1]:nodeSubdived[nodeIndxSubdived[eedgeId]+1];
5984 for(int j=0;j<nbOfEdges;j++)
5986 bool direct=desc[offset+j]>0;
5987 int edgeId=std::abs(desc[offset+j])-1;
5988 if(!INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodeSubdived[nodeIndxSubdived[edgeId]]).isQuadratic())
5990 int id1=nodeSubdived[nodeIndxSubdived[edgeId]+1];
5991 int id2=nodeSubdived[nodeIndxSubdived[edgeId+1]-1];
5992 int ref2=direct?id1:id2;
5995 int nbOfSubNodes=nodeIndxSubdived[edgeId+1]-nodeIndxSubdived[edgeId]-1;
5996 newConnLgth+=nbOfSubNodes-1;
6001 std::ostringstream oss; oss << "MEDCouplingUMesh::subDivide2DMesh : On polygon #" << i << " edgeid #" << j << " subedges mismatch : end subedge k!=start subedge k+1 !";
6002 throw INTERP_KERNEL::Exception(oss.str());
6007 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::subDivide2DMesh : this method only subdivides into linear edges !");
6010 newConnLgth++;//+1 is for cell type
6011 connI[1]=newConnLgth;
6014 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
6015 newConn->alloc(newConnLgth,1);
6016 int *work=newConn->getPointer();
6017 for(int i=0;i<nbOfCells;i++)
6019 *work++=INTERP_KERNEL::NORM_POLYGON;
6020 int offset=descIndex[i];
6021 int nbOfEdges=descIndex[i+1]-offset;
6022 for(int j=0;j<nbOfEdges;j++)
6024 bool direct=desc[offset+j]>0;
6025 int edgeId=std::abs(desc[offset+j])-1;
6027 work=std::copy(nodeSubdived+nodeIndxSubdived[edgeId]+1,nodeSubdived+nodeIndxSubdived[edgeId+1]-1,work);
6030 int nbOfSubNodes=nodeIndxSubdived[edgeId+1]-nodeIndxSubdived[edgeId]-1;
6031 std::reverse_iterator<const int *> it(nodeSubdived+nodeIndxSubdived[edgeId+1]);
6032 work=std::copy(it,it+nbOfSubNodes-1,work);
6036 DataArrayInt::SetArrayIn(newConn,_nodal_connec);
6039 _types.insert(INTERP_KERNEL::NORM_POLYGON);
6043 * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
6044 * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
6045 * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell. This method
6046 * does \b not perform geometrical checks and checks only nodal connectivity of cells,
6047 * so it can be useful to call mergeNodes() before calling this method.
6048 * \throw If \a this->getMeshDimension() <= 1.
6049 * \throw If the coordinates array is not set.
6050 * \throw If the nodal connectivity of cells is not defined.
6052 void MEDCouplingUMesh::convertDegeneratedCells()
6054 checkFullyDefined();
6055 if(getMeshDimension()<=1)
6056 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
6057 int nbOfCells=getNumberOfCells();
6060 int initMeshLgth=getNodalConnectivityArrayLen();
6061 int *conn=_nodal_connec->getPointer();
6062 int *index=_nodal_connec_index->getPointer();
6066 for(int i=0;i<nbOfCells;i++)
6068 lgthOfCurCell=index[i+1]-posOfCurCell;
6069 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
6071 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
6072 conn+newPos+1,newLgth);
6073 conn[newPos]=newType;
6075 posOfCurCell=index[i+1];
6078 if(newPos!=initMeshLgth)
6079 _nodal_connec->reAlloc(newPos);
6084 * Finds incorrectly oriented cells of this 2D mesh in 3D space.
6085 * A cell is considered to be oriented correctly if an angle between its
6086 * normal vector and a given vector is less than \c PI / \c 2.
6087 * \param [in] vec - 3 components of the vector specifying the correct orientation of
6089 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
6091 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
6092 * is not cleared before filling in.
6093 * \throw If \a this->getMeshDimension() != 2.
6094 * \throw If \a this->getSpaceDimension() != 3.
6096 * \if ENABLE_EXAMPLES
6097 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
6098 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
6101 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<int>& cells) const
6103 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6104 throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
6105 int nbOfCells=getNumberOfCells();
6106 const int *conn=_nodal_connec->getConstPointer();
6107 const int *connI=_nodal_connec_index->getConstPointer();
6108 const double *coordsPtr=_coords->getConstPointer();
6109 for(int i=0;i<nbOfCells;i++)
6111 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6112 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
6114 bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
6115 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6122 * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
6123 * considered to be oriented correctly if an angle between its normal vector and a
6124 * given vector is less than \c PI / \c 2.
6125 * \param [in] vec - 3 components of the vector specifying the correct orientation of
6127 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
6129 * \throw If \a this->getMeshDimension() != 2.
6130 * \throw If \a this->getSpaceDimension() != 3.
6132 * \if ENABLE_EXAMPLES
6133 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
6134 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
6137 * \sa changeOrientationOfCells
6139 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
6141 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6142 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
6143 int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
6144 const int *connI(_nodal_connec_index->getConstPointer());
6145 const double *coordsPtr(_coords->getConstPointer());
6146 bool isModified(false);
6147 for(int i=0;i<nbOfCells;i++)
6149 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6150 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
6152 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6153 bool isQuadratic(cm.isQuadratic());
6154 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6157 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6162 _nodal_connec->declareAsNew();
6167 * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
6169 * \sa orientCorrectly2DCells
6171 void MEDCouplingUMesh::changeOrientationOfCells()
6173 int mdim(getMeshDimension());
6174 if(mdim!=2 && mdim!=1)
6175 throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
6176 int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
6177 const int *connI(_nodal_connec_index->getConstPointer());
6180 for(int i=0;i<nbOfCells;i++)
6182 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6183 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6184 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6189 for(int i=0;i<nbOfCells;i++)
6191 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6192 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6193 cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6199 * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
6200 * oriented facets. The normal vector of the facet should point out of the cell.
6201 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
6202 * is not cleared before filling in.
6203 * \throw If \a this->getMeshDimension() != 3.
6204 * \throw If \a this->getSpaceDimension() != 3.
6205 * \throw If the coordinates array is not set.
6206 * \throw If the nodal connectivity of cells is not defined.
6208 * \if ENABLE_EXAMPLES
6209 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
6210 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
6213 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<int>& cells) const
6215 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6216 throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
6217 int nbOfCells=getNumberOfCells();
6218 const int *conn=_nodal_connec->getConstPointer();
6219 const int *connI=_nodal_connec_index->getConstPointer();
6220 const double *coordsPtr=_coords->getConstPointer();
6221 for(int i=0;i<nbOfCells;i++)
6223 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6224 if(type==INTERP_KERNEL::NORM_POLYHED)
6226 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6233 * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
6235 * \throw If \a this->getMeshDimension() != 3.
6236 * \throw If \a this->getSpaceDimension() != 3.
6237 * \throw If the coordinates array is not set.
6238 * \throw If the nodal connectivity of cells is not defined.
6239 * \throw If the reparation fails.
6241 * \if ENABLE_EXAMPLES
6242 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
6243 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
6245 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
6247 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
6249 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6250 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
6251 int nbOfCells=getNumberOfCells();
6252 int *conn=_nodal_connec->getPointer();
6253 const int *connI=_nodal_connec_index->getConstPointer();
6254 const double *coordsPtr=_coords->getConstPointer();
6255 for(int i=0;i<nbOfCells;i++)
6257 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6258 if(type==INTERP_KERNEL::NORM_POLYHED)
6262 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6263 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
6265 catch(INTERP_KERNEL::Exception& e)
6267 std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
6268 throw INTERP_KERNEL::Exception(oss.str());
6276 * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
6277 * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
6278 * according to which the first facet of the cell should be oriented to have the normal vector
6279 * pointing out of cell.
6280 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of fixed
6281 * cells. The caller is to delete this array using decrRef() as it is no more
6283 * \throw If \a this->getMeshDimension() != 3.
6284 * \throw If \a this->getSpaceDimension() != 3.
6285 * \throw If the coordinates array is not set.
6286 * \throw If the nodal connectivity of cells is not defined.
6288 * \if ENABLE_EXAMPLES
6289 * \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
6290 * \ref py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
6292 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
6294 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
6296 const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
6297 if(getMeshDimension()!=3)
6298 throw INTERP_KERNEL::Exception(msg);
6299 int spaceDim=getSpaceDimension();
6301 throw INTERP_KERNEL::Exception(msg);
6303 int nbOfCells=getNumberOfCells();
6304 int *conn=_nodal_connec->getPointer();
6305 const int *connI=_nodal_connec_index->getConstPointer();
6306 const double *coo=getCoords()->getConstPointer();
6307 MCAuto<DataArrayInt> cells(DataArrayInt::New()); cells->alloc(0,1);
6308 for(int i=0;i<nbOfCells;i++)
6310 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6311 if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
6313 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
6315 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
6316 cells->pushBackSilent(i);
6320 return cells.retn();
6324 * This method is a faster method to correct orientation of all 3D cells in \a this.
6325 * 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.
6326 * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
6328 * \return a newly allocated int array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
6329 * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
6331 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
6333 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6334 throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
6335 int nbOfCells=getNumberOfCells();
6336 int *conn=_nodal_connec->getPointer();
6337 const int *connI=_nodal_connec_index->getConstPointer();
6338 const double *coordsPtr=_coords->getConstPointer();
6339 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
6340 for(int i=0;i<nbOfCells;i++)
6342 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6345 case INTERP_KERNEL::NORM_TETRA4:
6347 if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6349 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
6350 ret->pushBackSilent(i);
6354 case INTERP_KERNEL::NORM_PYRA5:
6356 if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6358 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
6359 ret->pushBackSilent(i);
6363 case INTERP_KERNEL::NORM_PENTA6:
6364 case INTERP_KERNEL::NORM_HEXA8:
6365 case INTERP_KERNEL::NORM_HEXGP12:
6367 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6369 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
6370 ret->pushBackSilent(i);
6374 case INTERP_KERNEL::NORM_POLYHED:
6376 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6378 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
6379 ret->pushBackSilent(i);
6384 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 !");
6392 * This method has a sense for meshes with spaceDim==3 and meshDim==2.
6393 * If it is not the case an exception will be thrown.
6394 * This method is fast because the first cell of \a this is used to compute the plane.
6395 * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
6396 * \param pos output of size at least 3 used to store a point owned of searched plane.
6398 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
6400 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6401 throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
6402 const int *conn=_nodal_connec->getConstPointer();
6403 const int *connI=_nodal_connec_index->getConstPointer();
6404 const double *coordsPtr=_coords->getConstPointer();
6405 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
6406 std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
6410 * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
6411 * cells. Currently cells of the following types are treated:
6412 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
6413 * For a cell of other type an exception is thrown.
6414 * Space dimension of a 2D mesh can be either 2 or 3.
6415 * The Edge Ratio of a cell \f$t\f$ is:
6416 * \f$\frac{|t|_\infty}{|t|_0}\f$,
6417 * where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
6418 * the smallest edge lengths of \f$t\f$.
6419 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6420 * cells and one time, lying on \a this mesh. The caller is to delete this
6421 * field using decrRef() as it is no more needed.
6422 * \throw If the coordinates array is not set.
6423 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6424 * \throw If the connectivity data array has more than one component.
6425 * \throw If the connectivity data array has a named component.
6426 * \throw If the connectivity index data array has more than one component.
6427 * \throw If the connectivity index data array has a named component.
6428 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
6429 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
6430 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
6432 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
6434 checkConsistencyLight();
6435 int spaceDim=getSpaceDimension();
6436 int meshDim=getMeshDimension();
6437 if(spaceDim!=2 && spaceDim!=3)
6438 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
6439 if(meshDim!=2 && meshDim!=3)
6440 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
6441 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6443 int nbOfCells=getNumberOfCells();
6444 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6445 arr->alloc(nbOfCells,1);
6446 double *pt=arr->getPointer();
6447 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6448 const int *conn=_nodal_connec->getConstPointer();
6449 const int *connI=_nodal_connec_index->getConstPointer();
6450 const double *coo=_coords->getConstPointer();
6452 for(int i=0;i<nbOfCells;i++,pt++)
6454 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6457 case INTERP_KERNEL::NORM_TRI3:
6459 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
6460 *pt=INTERP_KERNEL::triEdgeRatio(tmp);
6463 case INTERP_KERNEL::NORM_QUAD4:
6465 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6466 *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
6469 case INTERP_KERNEL::NORM_TETRA4:
6471 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6472 *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
6476 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
6478 conn+=connI[i+1]-connI[i];
6480 ret->setName("EdgeRatio");
6481 ret->synchronizeTimeWithSupport();
6486 * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
6487 * cells. Currently cells of the following types are treated:
6488 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
6489 * For a cell of other type an exception is thrown.
6490 * Space dimension of a 2D mesh can be either 2 or 3.
6491 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6492 * cells and one time, lying on \a this mesh. The caller is to delete this
6493 * field using decrRef() as it is no more needed.
6494 * \throw If the coordinates array is not set.
6495 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6496 * \throw If the connectivity data array has more than one component.
6497 * \throw If the connectivity data array has a named component.
6498 * \throw If the connectivity index data array has more than one component.
6499 * \throw If the connectivity index data array has a named component.
6500 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
6501 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
6502 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
6504 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
6506 checkConsistencyLight();
6507 int spaceDim=getSpaceDimension();
6508 int meshDim=getMeshDimension();
6509 if(spaceDim!=2 && spaceDim!=3)
6510 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
6511 if(meshDim!=2 && meshDim!=3)
6512 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
6513 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6515 int nbOfCells=getNumberOfCells();
6516 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6517 arr->alloc(nbOfCells,1);
6518 double *pt=arr->getPointer();
6519 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6520 const int *conn=_nodal_connec->getConstPointer();
6521 const int *connI=_nodal_connec_index->getConstPointer();
6522 const double *coo=_coords->getConstPointer();
6524 for(int i=0;i<nbOfCells;i++,pt++)
6526 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6529 case INTERP_KERNEL::NORM_TRI3:
6531 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
6532 *pt=INTERP_KERNEL::triAspectRatio(tmp);
6535 case INTERP_KERNEL::NORM_QUAD4:
6537 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6538 *pt=INTERP_KERNEL::quadAspectRatio(tmp);
6541 case INTERP_KERNEL::NORM_TETRA4:
6543 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6544 *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
6548 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
6550 conn+=connI[i+1]-connI[i];
6552 ret->setName("AspectRatio");
6553 ret->synchronizeTimeWithSupport();
6558 * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
6559 * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
6560 * in 3D space. Currently only cells of the following types are
6561 * treated: INTERP_KERNEL::NORM_QUAD4.
6562 * For a cell of other type an exception is thrown.
6563 * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
6565 * \f$t=\vec{da}\times\vec{ab}\f$,
6566 * \f$u=\vec{ab}\times\vec{bc}\f$
6567 * \f$v=\vec{bc}\times\vec{cd}\f$
6568 * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
6570 * W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
6572 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6573 * cells and one time, lying on \a this mesh. The caller is to delete this
6574 * field using decrRef() as it is no more needed.
6575 * \throw If the coordinates array is not set.
6576 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6577 * \throw If the connectivity data array has more than one component.
6578 * \throw If the connectivity data array has a named component.
6579 * \throw If the connectivity index data array has more than one component.
6580 * \throw If the connectivity index data array has a named component.
6581 * \throw If \a this->getMeshDimension() != 2.
6582 * \throw If \a this->getSpaceDimension() != 3.
6583 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
6585 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
6587 checkConsistencyLight();
6588 int spaceDim=getSpaceDimension();
6589 int meshDim=getMeshDimension();
6591 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
6593 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
6594 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6596 int nbOfCells=getNumberOfCells();
6597 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6598 arr->alloc(nbOfCells,1);
6599 double *pt=arr->getPointer();
6600 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6601 const int *conn=_nodal_connec->getConstPointer();
6602 const int *connI=_nodal_connec_index->getConstPointer();
6603 const double *coo=_coords->getConstPointer();
6605 for(int i=0;i<nbOfCells;i++,pt++)
6607 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6610 case INTERP_KERNEL::NORM_QUAD4:
6612 FillInCompact3DMode(3,4,conn+1,coo,tmp);
6613 *pt=INTERP_KERNEL::quadWarp(tmp);
6617 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
6619 conn+=connI[i+1]-connI[i];
6621 ret->setName("Warp");
6622 ret->synchronizeTimeWithSupport();
6628 * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
6629 * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
6630 * treated: INTERP_KERNEL::NORM_QUAD4.
6631 * The skew is computed as follow for a quad with points (a,b,c,d): let
6632 * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
6633 * then the skew is computed as:
6635 * s=\frac{u}{|u|}\cdot\frac{v}{|v|}
6638 * For a cell of other type an exception is thrown.
6639 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6640 * cells and one time, lying on \a this mesh. The caller is to delete this
6641 * field using decrRef() as it is no more needed.
6642 * \throw If the coordinates array is not set.
6643 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6644 * \throw If the connectivity data array has more than one component.
6645 * \throw If the connectivity data array has a named component.
6646 * \throw If the connectivity index data array has more than one component.
6647 * \throw If the connectivity index data array has a named component.
6648 * \throw If \a this->getMeshDimension() != 2.
6649 * \throw If \a this->getSpaceDimension() != 3.
6650 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
6652 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
6654 checkConsistencyLight();
6655 int spaceDim=getSpaceDimension();
6656 int meshDim=getMeshDimension();
6658 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
6660 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
6661 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6663 int nbOfCells=getNumberOfCells();
6664 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6665 arr->alloc(nbOfCells,1);
6666 double *pt=arr->getPointer();
6667 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6668 const int *conn=_nodal_connec->getConstPointer();
6669 const int *connI=_nodal_connec_index->getConstPointer();
6670 const double *coo=_coords->getConstPointer();
6672 for(int i=0;i<nbOfCells;i++,pt++)
6674 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6677 case INTERP_KERNEL::NORM_QUAD4:
6679 FillInCompact3DMode(3,4,conn+1,coo,tmp);
6680 *pt=INTERP_KERNEL::quadSkew(tmp);
6684 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
6686 conn+=connI[i+1]-connI[i];
6688 ret->setName("Skew");
6689 ret->synchronizeTimeWithSupport();
6694 * 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.
6696 * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
6698 * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
6700 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
6702 checkConsistencyLight();
6703 MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
6705 std::set<INTERP_KERNEL::NormalizedCellType> types;
6706 ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
6707 int spaceDim(getSpaceDimension()),nbCells(getNumberOfCells());
6708 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6709 arr->alloc(nbCells,1);
6710 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
6712 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
6713 MCAuto<DataArrayInt> cellIds(giveCellsWithType(*it));
6714 dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
6717 ret->setName("Diameter");
6722 * This method aggregate the bbox of each cell and put it into bbox parameter (xmin,xmax,ymin,ymax,zmin,zmax).
6724 * \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)
6725 * For all other cases this input parameter is ignored.
6726 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6728 * \throw If \a this is not fully set (coordinates and connectivity).
6729 * \throw If a cell in \a this has no valid nodeId.
6730 * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
6732 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
6734 int mDim(getMeshDimension()),sDim(getSpaceDimension());
6735 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.
6736 return getBoundingBoxForBBTreeFast();
6737 if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
6739 bool presenceOfQuadratic(false);
6740 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
6742 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
6743 if(cm.isQuadratic())
6744 presenceOfQuadratic=true;
6746 if(!presenceOfQuadratic)
6747 return getBoundingBoxForBBTreeFast();
6748 if(mDim==2 && sDim==2)
6749 return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
6751 return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
6753 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) !");
6757 * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
6758 * So meshes having quadratic cells the computed bounding boxes can be invalid !
6760 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6762 * \throw If \a this is not fully set (coordinates and connectivity).
6763 * \throw If a cell in \a this has no valid nodeId.
6765 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
6767 checkFullyDefined();
6768 int spaceDim(getSpaceDimension()),nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
6769 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6770 double *bbox(ret->getPointer());
6771 for(int i=0;i<nbOfCells*spaceDim;i++)
6773 bbox[2*i]=std::numeric_limits<double>::max();
6774 bbox[2*i+1]=-std::numeric_limits<double>::max();
6776 const double *coordsPtr(_coords->getConstPointer());
6777 const int *conn(_nodal_connec->getConstPointer()),*connI(_nodal_connec_index->getConstPointer());
6778 for(int i=0;i<nbOfCells;i++)
6780 int offset=connI[i]+1;
6781 int nbOfNodesForCell(connI[i+1]-offset),kk(0);
6782 for(int j=0;j<nbOfNodesForCell;j++)
6784 int nodeId=conn[offset+j];
6785 if(nodeId>=0 && nodeId<nbOfNodes)
6787 for(int k=0;k<spaceDim;k++)
6789 bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
6790 bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
6797 std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
6798 throw INTERP_KERNEL::Exception(oss.str());
6805 * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
6806 * useful for 2D meshes having quadratic cells
6807 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
6808 * the two extremities of the arc of circle).
6810 * \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)
6811 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6812 * \throw If \a this is not fully defined.
6813 * \throw If \a this is not a mesh with meshDimension equal to 2.
6814 * \throw If \a this is not a mesh with spaceDimension equal to 2.
6815 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
6817 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
6819 checkFullyDefined();
6820 int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
6821 if(spaceDim!=2 || mDim!=2)
6822 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!");
6823 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6824 double *bbox(ret->getPointer());
6825 const double *coords(_coords->getConstPointer());
6826 const int *conn(_nodal_connec->getConstPointer()),*connI(_nodal_connec_index->getConstPointer());
6827 for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
6829 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
6830 int sz(connI[1]-connI[0]-1);
6831 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=arcDetEps;
6832 std::vector<INTERP_KERNEL::Node *> nodes(sz);
6833 INTERP_KERNEL::QuadraticPolygon *pol(0);
6834 for(int j=0;j<sz;j++)
6836 int nodeId(conn[*connI+1+j]);
6837 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
6839 if(!cm.isQuadratic())
6840 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
6842 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
6843 INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
6844 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
6850 * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
6851 * useful for 2D meshes having quadratic cells
6852 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
6853 * the two extremities of the arc of circle).
6855 * \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)
6856 * \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 defined.
6858 * \throw If \a this is not a mesh with meshDimension equal to 1.
6859 * \throw If \a this is not a mesh with spaceDimension equal to 2.
6860 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
6862 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
6864 checkFullyDefined();
6865 int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
6866 if(spaceDim!=2 || mDim!=1)
6867 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!");
6868 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6869 double *bbox(ret->getPointer());
6870 const double *coords(_coords->getConstPointer());
6871 const int *conn(_nodal_connec->getConstPointer()),*connI(_nodal_connec_index->getConstPointer());
6872 for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
6874 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
6875 int sz(connI[1]-connI[0]-1);
6876 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=arcDetEps;
6877 std::vector<INTERP_KERNEL::Node *> nodes(sz);
6878 INTERP_KERNEL::Edge *edge(0);
6879 for(int j=0;j<sz;j++)
6881 int nodeId(conn[*connI+1+j]);
6882 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
6884 if(!cm.isQuadratic())
6885 edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
6887 edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
6888 const INTERP_KERNEL::Bounds& b(edge->getBounds());
6889 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
6896 namespace MEDCouplingImpl
6901 ConnReader(const int *c, int val):_conn(c),_val(val) { }
6902 bool operator() (const int& pos) { return _conn[pos]!=_val; }
6911 ConnReader2(const int *c, int val):_conn(c),_val(val) { }
6912 bool operator() (const int& pos) { return _conn[pos]==_val; }
6922 * This method expects that \a this is sorted by types. If not an exception will be thrown.
6923 * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
6924 * \a this is composed in cell types.
6925 * The returned array is of size 3*n where n is the number of different types present in \a this.
6926 * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
6927 * This parameter is kept only for compatibility with other methode listed above.
6929 std::vector<int> MEDCouplingUMesh::getDistributionOfTypes() const
6931 checkConnectivityFullyDefined();
6932 const int *conn=_nodal_connec->getConstPointer();
6933 const int *connI=_nodal_connec_index->getConstPointer();
6934 const int *work=connI;
6935 int nbOfCells=getNumberOfCells();
6936 std::size_t n=getAllGeoTypes().size();
6937 std::vector<int> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
6938 std::set<INTERP_KERNEL::NormalizedCellType> types;
6939 for(std::size_t i=0;work!=connI+nbOfCells;i++)
6941 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
6942 if(types.find(typ)!=types.end())
6944 std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
6945 oss << " is not contiguous !";
6946 throw INTERP_KERNEL::Exception(oss.str());
6950 const int *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
6951 ret[3*i+1]=(int)std::distance(work,work2);
6958 * This method is used to check that this has contiguous cell type in same order than described in \a code.
6959 * only for types cell, type node is not managed.
6960 * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
6961 * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
6962 * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
6963 * If 2 or more same geometric type is in \a code and exception is thrown too.
6965 * This method firstly checks
6966 * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
6967 * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
6968 * an exception is thrown too.
6970 * If all geometric types in \a code are exactly those in \a this null pointer is returned.
6971 * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
6972 * and a DataArrayInt instance is returned that the user has the responsability to deallocate.
6974 DataArrayInt *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<int>& code, const std::vector<const DataArrayInt *>& idsPerType) const
6977 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
6978 std::size_t sz=code.size();
6981 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
6982 std::vector<INTERP_KERNEL::NormalizedCellType> types;
6984 bool isNoPflUsed=true;
6985 for(std::size_t i=0;i<n;i++)
6986 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
6988 types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
6990 if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
6991 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
6992 isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
6995 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
6998 if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
6999 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
7000 if(types.size()==_types.size())
7003 MCAuto<DataArrayInt> ret=DataArrayInt::New();
7005 int *retPtr=ret->getPointer();
7006 const int *connI=_nodal_connec_index->getConstPointer();
7007 const int *conn=_nodal_connec->getConstPointer();
7008 int nbOfCells=getNumberOfCells();
7011 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
7013 i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,(int)(*it)));
7014 int offset=(int)std::distance(connI,i);
7015 const int *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)(*it)));
7016 int nbOfCellsOfCurType=(int)std::distance(i,j);
7017 if(code[3*kk+2]==-1)
7018 for(int k=0;k<nbOfCellsOfCurType;k++)
7022 int idInIdsPerType=code[3*kk+2];
7023 if(idInIdsPerType>=0 && idInIdsPerType<(int)idsPerType.size())
7025 const DataArrayInt *zePfl=idsPerType[idInIdsPerType];
7028 zePfl->checkAllocated();
7029 if(zePfl->getNumberOfComponents()==1)
7031 for(const int *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
7033 if(*k>=0 && *k<nbOfCellsOfCurType)
7034 *retPtr=(*k)+offset;
7037 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
7038 oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
7039 throw INTERP_KERNEL::Exception(oss.str());
7044 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
7047 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
7051 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
7052 oss << " should be in [0," << idsPerType.size() << ") !";
7053 throw INTERP_KERNEL::Exception(oss.str());
7062 * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
7063 * 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.
7064 * 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.
7065 * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
7067 * \param [in] profile
7068 * \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.
7069 * \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,
7070 * \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
7071 * \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.
7072 * This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
7073 * \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
7075 void MEDCouplingUMesh::splitProfilePerType(const DataArrayInt *profile, std::vector<int>& code, std::vector<DataArrayInt *>& idsInPflPerType, std::vector<DataArrayInt *>& idsPerType) const
7078 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
7079 if(profile->getNumberOfComponents()!=1)
7080 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
7081 checkConnectivityFullyDefined();
7082 const int *conn=_nodal_connec->getConstPointer();
7083 const int *connI=_nodal_connec_index->getConstPointer();
7084 int nbOfCells=getNumberOfCells();
7085 std::vector<INTERP_KERNEL::NormalizedCellType> types;
7086 std::vector<int> typeRangeVals(1);
7087 for(const int *i=connI;i!=connI+nbOfCells;)
7089 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7090 if(std::find(types.begin(),types.end(),curType)!=types.end())
7092 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
7094 types.push_back(curType);
7095 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7096 typeRangeVals.push_back((int)std::distance(connI,i));
7099 DataArrayInt *castArr=0,*rankInsideCast=0,*castsPresent=0;
7100 profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
7101 MCAuto<DataArrayInt> tmp0=castArr;
7102 MCAuto<DataArrayInt> tmp1=rankInsideCast;
7103 MCAuto<DataArrayInt> tmp2=castsPresent;
7105 int nbOfCastsFinal=castsPresent->getNumberOfTuples();
7106 code.resize(3*nbOfCastsFinal);
7107 std::vector< MCAuto<DataArrayInt> > idsInPflPerType2;
7108 std::vector< MCAuto<DataArrayInt> > idsPerType2;
7109 for(int i=0;i<nbOfCastsFinal;i++)
7111 int castId=castsPresent->getIJ(i,0);
7112 MCAuto<DataArrayInt> tmp3=castArr->findIdsEqual(castId);
7113 idsInPflPerType2.push_back(tmp3);
7114 code[3*i]=(int)types[castId];
7115 code[3*i+1]=tmp3->getNumberOfTuples();
7116 MCAuto<DataArrayInt> tmp4=rankInsideCast->selectByTupleId(tmp3->getConstPointer(),tmp3->getConstPointer()+tmp3->getNumberOfTuples());
7117 if(!tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
7119 tmp4->copyStringInfoFrom(*profile);
7120 idsPerType2.push_back(tmp4);
7121 code[3*i+2]=(int)idsPerType2.size()-1;
7128 std::size_t sz2=idsInPflPerType2.size();
7129 idsInPflPerType.resize(sz2);
7130 for(std::size_t i=0;i<sz2;i++)
7132 DataArrayInt *locDa=idsInPflPerType2[i];
7134 idsInPflPerType[i]=locDa;
7136 std::size_t sz=idsPerType2.size();
7137 idsPerType.resize(sz);
7138 for(std::size_t i=0;i<sz;i++)
7140 DataArrayInt *locDa=idsPerType2[i];
7142 idsPerType[i]=locDa;
7147 * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
7148 * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
7149 * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
7150 * 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.
7152 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *&revDesc, DataArrayInt *&revDescIndx, DataArrayInt *& nM1LevMeshIds, DataArrayInt *&meshnM1Old2New) const
7154 checkFullyDefined();
7155 nM1LevMesh->checkFullyDefined();
7156 if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
7157 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
7158 if(_coords!=nM1LevMesh->getCoords())
7159 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
7160 MCAuto<DataArrayInt> tmp0=DataArrayInt::New();
7161 MCAuto<DataArrayInt> tmp1=DataArrayInt::New();
7162 MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
7163 MCAuto<DataArrayInt> ret0=ret1->sortCellsInMEDFileFrmt();
7164 desc->transformWithIndArr(ret0->getConstPointer(),ret0->getConstPointer()+ret0->getNbOfElems());
7165 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
7166 tmp->setConnectivity(tmp0,tmp1);
7167 tmp->renumberCells(ret0->getConstPointer(),false);
7168 revDesc=tmp->getNodalConnectivity();
7169 revDescIndx=tmp->getNodalConnectivityIndex();
7170 DataArrayInt *ret=0;
7171 if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
7174 ret->getMaxValue(tmp2);
7176 std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
7177 throw INTERP_KERNEL::Exception(oss.str());
7182 revDescIndx->incrRef();
7185 meshnM1Old2New=ret0;
7190 * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
7191 * necessary for writing the mesh to MED file. Additionally returns a permutation array
7192 * in "Old to New" mode.
7193 * \return DataArrayInt * - a new instance of DataArrayInt. The caller is to delete
7194 * this array using decrRef() as it is no more needed.
7195 * \throw If the nodal connectivity of cells is not defined.
7197 DataArrayInt *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
7199 checkConnectivityFullyDefined();
7200 MCAuto<DataArrayInt> ret=getRenumArrForMEDFileFrmt();
7201 renumberCells(ret->getConstPointer(),false);
7206 * This methods checks that cells are sorted by their types.
7207 * This method makes asumption (no check) that connectivity is correctly set before calling.
7209 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
7211 checkFullyDefined();
7212 const int *conn=_nodal_connec->getConstPointer();
7213 const int *connI=_nodal_connec_index->getConstPointer();
7214 int nbOfCells=getNumberOfCells();
7215 std::set<INTERP_KERNEL::NormalizedCellType> types;
7216 for(const int *i=connI;i!=connI+nbOfCells;)
7218 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7219 if(types.find(curType)!=types.end())
7221 types.insert(curType);
7222 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7228 * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
7229 * The geometric type order is specified by MED file.
7231 * \sa MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
7233 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
7235 return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
7239 * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
7240 * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
7241 * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
7242 * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
7244 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
7246 checkFullyDefined();
7247 const int *conn=_nodal_connec->getConstPointer();
7248 const int *connI=_nodal_connec_index->getConstPointer();
7249 int nbOfCells=getNumberOfCells();
7253 std::set<INTERP_KERNEL::NormalizedCellType> sg;
7254 for(const int *i=connI;i!=connI+nbOfCells;)
7256 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7257 const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
7258 if(isTypeExists!=orderEnd)
7260 int pos=(int)std::distance(orderBg,isTypeExists);
7264 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7268 if(sg.find(curType)==sg.end())
7270 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7281 * This method returns 2 newly allocated DataArrayInt instances. The first is an array of size 'this->getNumberOfCells()' with one component,
7282 * 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
7283 * 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'.
7285 DataArrayInt *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayInt *&nbPerType) const
7287 checkConnectivityFullyDefined();
7288 int nbOfCells=getNumberOfCells();
7289 const int *conn=_nodal_connec->getConstPointer();
7290 const int *connI=_nodal_connec_index->getConstPointer();
7291 MCAuto<DataArrayInt> tmpa=DataArrayInt::New();
7292 MCAuto<DataArrayInt> tmpb=DataArrayInt::New();
7293 tmpa->alloc(nbOfCells,1);
7294 tmpb->alloc((int)std::distance(orderBg,orderEnd),1);
7295 tmpb->fillWithZero();
7296 int *tmp=tmpa->getPointer();
7297 int *tmp2=tmpb->getPointer();
7298 for(const int *i=connI;i!=connI+nbOfCells;i++)
7300 const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
7303 int pos=(int)std::distance(orderBg,where);
7305 tmp[std::distance(connI,i)]=pos;
7309 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
7310 std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
7311 oss << " has a type " << cm.getRepr() << " not in input array of type !";
7312 throw INTERP_KERNEL::Exception(oss.str());
7315 nbPerType=tmpb.retn();
7320 * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
7322 * \return a new object containing the old to new correspondance.
7324 * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
7326 DataArrayInt *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
7328 return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
7332 * 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.
7333 * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
7334 * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
7335 * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
7337 DataArrayInt *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
7339 DataArrayInt *nbPerType=0;
7340 MCAuto<DataArrayInt> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
7341 nbPerType->decrRef();
7342 return tmpa->buildPermArrPerLevel();
7346 * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
7347 * The number of cells remains unchanged after the call of this method.
7348 * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
7349 * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
7351 * \return the array giving the correspondance old to new.
7353 DataArrayInt *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
7355 checkFullyDefined();
7357 const int *conn=_nodal_connec->getConstPointer();
7358 const int *connI=_nodal_connec_index->getConstPointer();
7359 int nbOfCells=getNumberOfCells();
7360 std::vector<INTERP_KERNEL::NormalizedCellType> types;
7361 for(const int *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
7362 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
7364 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7365 types.push_back(curType);
7366 for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
7368 DataArrayInt *ret=DataArrayInt::New();
7369 ret->alloc(nbOfCells,1);
7370 int *retPtr=ret->getPointer();
7371 std::fill(retPtr,retPtr+nbOfCells,-1);
7373 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
7375 for(const int *i=connI;i!=connI+nbOfCells;i++)
7376 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
7377 retPtr[std::distance(connI,i)]=newCellId++;
7379 renumberCells(retPtr,false);
7384 * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
7385 * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
7386 * This method makes asumption that connectivity is correctly set before calling.
7388 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
7390 checkConnectivityFullyDefined();
7391 const int *conn=_nodal_connec->getConstPointer();
7392 const int *connI=_nodal_connec_index->getConstPointer();
7393 int nbOfCells=getNumberOfCells();
7394 std::vector<MEDCouplingUMesh *> ret;
7395 for(const int *i=connI;i!=connI+nbOfCells;)
7397 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7398 int beginCellId=(int)std::distance(connI,i);
7399 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7400 int endCellId=(int)std::distance(connI,i);
7401 int sz=endCellId-beginCellId;
7402 int *cells=new int[sz];
7403 for(int j=0;j<sz;j++)
7404 cells[j]=beginCellId+j;
7405 MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
7413 * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
7414 * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
7415 * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
7417 * \return a newly allocated instance, that the caller must manage.
7418 * \throw If \a this contains more than one geometric type.
7419 * \throw If the nodal connectivity of \a this is not fully defined.
7420 * \throw If the internal data is not coherent.
7422 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
7424 checkConnectivityFullyDefined();
7425 if(_types.size()!=1)
7426 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7427 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
7428 MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
7429 ret->setCoords(getCoords());
7430 MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
7433 MCAuto<DataArrayInt> c=convertNodalConnectivityToStaticGeoTypeMesh();
7434 retC->setNodalConnectivity(c);
7438 MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
7440 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
7441 DataArrayInt *c=0,*ci=0;
7442 convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
7443 MCAuto<DataArrayInt> cs(c),cis(ci);
7444 retD->setNodalConnectivity(cs,cis);
7449 DataArrayInt *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
7451 checkConnectivityFullyDefined();
7452 if(_types.size()!=1)
7453 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7454 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
7455 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
7458 std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
7459 oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
7460 throw INTERP_KERNEL::Exception(oss.str());
7462 int nbCells=getNumberOfCells();
7464 int nbNodesPerCell=(int)cm.getNumberOfNodes();
7465 MCAuto<DataArrayInt> connOut=DataArrayInt::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
7466 int *outPtr=connOut->getPointer();
7467 const int *conn=_nodal_connec->begin();
7468 const int *connI=_nodal_connec_index->begin();
7470 for(int i=0;i<nbCells;i++,connI++)
7472 if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
7473 outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
7476 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 << ") !";
7477 throw INTERP_KERNEL::Exception(oss.str());
7480 return connOut.retn();
7484 * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
7485 * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
7489 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayInt *&nodalConn, DataArrayInt *&nodalConnIndex) const
7491 static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
7492 checkConnectivityFullyDefined();
7493 if(_types.size()!=1)
7494 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7495 int nbCells=getNumberOfCells(),lgth=_nodal_connec->getNumberOfTuples();
7497 throw INTERP_KERNEL::Exception(msg0);
7498 MCAuto<DataArrayInt> c(DataArrayInt::New()),ci(DataArrayInt::New());
7499 c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
7500 int *cp(c->getPointer()),*cip(ci->getPointer());
7501 const int *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
7503 for(int i=0;i<nbCells;i++,cip++,incip++)
7505 int strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
7506 int delta(stop-strt);
7509 if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
7510 cp=std::copy(incp+strt,incp+stop,cp);
7512 throw INTERP_KERNEL::Exception(msg0);
7515 throw INTERP_KERNEL::Exception(msg0);
7516 cip[1]=cip[0]+delta;
7518 nodalConn=c.retn(); nodalConnIndex=ci.retn();
7522 * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
7523 * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
7524 * This method is particulary useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
7525 * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
7526 * are not used here to avoid the build of big permutation array.
7528 * \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
7529 * those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
7530 * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayInt instance whose number of tuples is equal to the number of chunks of same geotype
7531 * in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
7532 * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayInt instance having the same size than \b szOfCellGrpOfSameType. This
7533 * output array gives for each chunck of same type the corresponding mesh id in \b ms.
7534 * \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
7535 * is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
7537 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
7538 DataArrayInt *&szOfCellGrpOfSameType,
7539 DataArrayInt *&idInMsOfCellGrpOfSameType)
7541 std::vector<const MEDCouplingUMesh *> ms2;
7542 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
7545 (*it)->checkConnectivityFullyDefined();
7549 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
7550 const DataArrayDouble *refCoo=ms2[0]->getCoords();
7551 int meshDim=ms2[0]->getMeshDimension();
7552 std::vector<const MEDCouplingUMesh *> m1ssm;
7553 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
7555 std::vector<const MEDCouplingUMesh *> m1ssmSingle;
7556 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
7558 MCAuto<DataArrayInt> ret1(DataArrayInt::New()),ret2(DataArrayInt::New());
7559 ret1->alloc(0,1); ret2->alloc(0,1);
7560 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
7562 if(meshDim!=(*it)->getMeshDimension())
7563 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
7564 if(refCoo!=(*it)->getCoords())
7565 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
7566 std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
7567 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
7568 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
7569 for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
7571 MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
7572 m1ssmSingleAuto.push_back(singleCell);
7573 m1ssmSingle.push_back(singleCell);
7574 ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
7577 MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
7578 MCAuto<DataArrayInt> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
7579 std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
7580 for(std::size_t i=0;i<m1ssm.size();i++)
7581 m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
7582 MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
7583 szOfCellGrpOfSameType=ret1->renumber(renum->getConstPointer());
7584 idInMsOfCellGrpOfSameType=ret2->renumber(renum->getConstPointer());
7589 * This method returns a newly created DataArrayInt instance.
7590 * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
7592 DataArrayInt *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const int *begin, const int *end) const
7594 checkFullyDefined();
7595 const int *conn=_nodal_connec->getConstPointer();
7596 const int *connIndex=_nodal_connec_index->getConstPointer();
7597 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
7598 for(const int *w=begin;w!=end;w++)
7599 if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
7600 ret->pushBackSilent(*w);
7605 * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
7606 * are in [0:getNumberOfCells())
7608 DataArrayInt *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayInt *da) const
7610 checkFullyDefined();
7611 const int *conn=_nodal_connec->getConstPointer();
7612 const int *connI=_nodal_connec_index->getConstPointer();
7613 int nbOfCells=getNumberOfCells();
7614 std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
7615 int *tmp=new int[nbOfCells];
7616 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
7619 for(const int *i=connI;i!=connI+nbOfCells;i++)
7620 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
7621 tmp[std::distance(connI,i)]=j++;
7623 DataArrayInt *ret=DataArrayInt::New();
7624 ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
7625 ret->copyStringInfoFrom(*da);
7626 int *retPtr=ret->getPointer();
7627 const int *daPtr=da->getConstPointer();
7628 int nbOfElems=da->getNbOfElems();
7629 for(int k=0;k<nbOfElems;k++)
7630 retPtr[k]=tmp[daPtr[k]];
7636 * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
7637 * This method \b works \b for mesh sorted by type.
7638 * cells whose ids is in 'idsPerGeoType' array.
7639 * This method conserves coords and name of mesh.
7641 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const int *idsPerGeoTypeBg, const int *idsPerGeoTypeEnd) const
7643 std::vector<int> code=getDistributionOfTypes();
7644 std::size_t nOfTypesInThis=code.size()/3;
7645 int sz=0,szOfType=0;
7646 for(std::size_t i=0;i<nOfTypesInThis;i++)
7651 szOfType=code[3*i+1];
7653 for(const int *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
7654 if(*work<0 || *work>=szOfType)
7656 std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
7657 oss << ". It should be in [0," << szOfType << ") !";
7658 throw INTERP_KERNEL::Exception(oss.str());
7660 MCAuto<DataArrayInt> idsTokeep=DataArrayInt::New(); idsTokeep->alloc(sz+(int)std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
7661 int *idsPtr=idsTokeep->getPointer();
7663 for(std::size_t i=0;i<nOfTypesInThis;i++)
7666 for(int j=0;j<code[3*i+1];j++)
7669 idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind2nd(std::plus<int>(),offset));
7670 offset+=code[3*i+1];
7672 MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
7673 ret->copyTinyInfoFrom(this);
7678 * This method returns a vector of size 'this->getNumberOfCells()'.
7679 * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
7681 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
7683 int ncell=getNumberOfCells();
7684 std::vector<bool> ret(ncell);
7685 const int *cI=getNodalConnectivityIndex()->getConstPointer();
7686 const int *c=getNodalConnectivity()->getConstPointer();
7687 for(int i=0;i<ncell;i++)
7689 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
7690 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
7691 ret[i]=cm.isQuadratic();
7697 * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
7699 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
7701 if(other->getType()!=UNSTRUCTURED)
7702 throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
7703 const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
7704 return MergeUMeshes(this,otherC);
7708 * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
7709 * computed by averaging coordinates of cell nodes, so this method is not a right
7710 * choice for degnerated meshes (not well oriented, cells with measure close to zero).
7711 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
7712 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
7713 * components. The caller is to delete this array using decrRef() as it is
7715 * \throw If the coordinates array is not set.
7716 * \throw If the nodal connectivity of cells is not defined.
7717 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
7719 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
7721 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
7722 int spaceDim=getSpaceDimension();
7723 int nbOfCells=getNumberOfCells();
7724 ret->alloc(nbOfCells,spaceDim);
7725 ret->copyStringInfoFrom(*getCoords());
7726 double *ptToFill=ret->getPointer();
7727 const int *nodal=_nodal_connec->getConstPointer();
7728 const int *nodalI=_nodal_connec_index->getConstPointer();
7729 const double *coor=_coords->getConstPointer();
7730 for(int i=0;i<nbOfCells;i++)
7732 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
7733 INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
7740 * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
7741 * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
7743 * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
7744 * DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
7746 * \sa MEDCouplingUMesh::computeCellCenterOfMass
7747 * \throw If \a this is not fully defined (coordinates and connectivity)
7748 * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
7750 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
7752 checkFullyDefined();
7753 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
7754 int spaceDim=getSpaceDimension();
7755 int nbOfCells=getNumberOfCells();
7756 int nbOfNodes=getNumberOfNodes();
7757 ret->alloc(nbOfCells,spaceDim);
7758 double *ptToFill=ret->getPointer();
7759 const int *nodal=_nodal_connec->getConstPointer();
7760 const int *nodalI=_nodal_connec_index->getConstPointer();
7761 const double *coor=_coords->getConstPointer();
7762 for(int i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
7764 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
7765 std::fill(ptToFill,ptToFill+spaceDim,0.);
7766 if(type!=INTERP_KERNEL::NORM_POLYHED)
7768 for(const int *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
7770 if(*conn>=0 && *conn<nbOfNodes)
7771 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
7774 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," << nbOfNodes << ") !";
7775 throw INTERP_KERNEL::Exception(oss.str());
7778 int nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
7779 if(nbOfNodesInCell>0)
7780 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
7783 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
7784 throw INTERP_KERNEL::Exception(oss.str());
7789 std::set<int> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
7791 for(std::set<int>::const_iterator it=s.begin();it!=s.end();it++)
7793 if(*it>=0 && *it<nbOfNodes)
7794 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
7797 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," << nbOfNodes << ") !";
7798 throw INTERP_KERNEL::Exception(oss.str());
7802 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)s.size()));
7805 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
7806 throw INTERP_KERNEL::Exception(oss.str());
7814 * Returns a new DataArrayDouble holding barycenters of specified cells. The
7815 * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
7816 * are specified via an array of cell ids.
7817 * \warning Validity of the specified cell ids is not checked!
7818 * Valid range is [ 0, \a this->getNumberOfCells() ).
7819 * \param [in] begin - an array of cell ids of interest.
7820 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
7821 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
7822 * end - \a begin ) tuples per \a this->getSpaceDimension() components. The
7823 * caller is to delete this array using decrRef() as it is no more needed.
7824 * \throw If the coordinates array is not set.
7825 * \throw If the nodal connectivity of cells is not defined.
7827 * \if ENABLE_EXAMPLES
7828 * \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
7829 * \ref py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
7832 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const int *begin, const int *end) const
7834 DataArrayDouble *ret=DataArrayDouble::New();
7835 int spaceDim=getSpaceDimension();
7836 int nbOfTuple=(int)std::distance(begin,end);
7837 ret->alloc(nbOfTuple,spaceDim);
7838 double *ptToFill=ret->getPointer();
7839 double *tmp=new double[spaceDim];
7840 const int *nodal=_nodal_connec->getConstPointer();
7841 const int *nodalI=_nodal_connec_index->getConstPointer();
7842 const double *coor=_coords->getConstPointer();
7843 for(const int *w=begin;w!=end;w++)
7845 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
7846 INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
7854 * 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".
7855 * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
7856 * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
7857 * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
7858 * This method is useful to detect 2D cells in 3D space that are not coplanar.
7860 * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
7861 * \throw If spaceDim!=3 or meshDim!=2.
7862 * \throw If connectivity of \a this is invalid.
7863 * \throw If connectivity of a cell in \a this points to an invalid node.
7865 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
7867 MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
7868 int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
7869 if(getSpaceDimension()!=3 || getMeshDimension()!=2)
7870 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
7871 ret->alloc(nbOfCells,4);
7872 double *retPtr(ret->getPointer());
7873 const int *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
7874 const double *coor(_coords->begin());
7875 for(int i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
7877 double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
7878 if(nodalI[1]-nodalI[0]>=3)
7880 for(int j=0;j<3;j++)
7882 int nodeId(nodal[nodalI[0]+1+j]);
7883 if(nodeId>=0 && nodeId<nbOfNodes)
7884 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
7887 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
7888 throw INTERP_KERNEL::Exception(oss.str());
7894 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
7895 throw INTERP_KERNEL::Exception(oss.str());
7897 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
7898 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
7904 * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
7907 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
7910 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
7911 da->checkAllocated();
7912 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(da->getName(),0);
7914 int nbOfTuples=da->getNumberOfTuples();
7915 MCAuto<DataArrayInt> c=DataArrayInt::New();
7916 MCAuto<DataArrayInt> cI=DataArrayInt::New();
7917 c->alloc(2*nbOfTuples,1);
7918 cI->alloc(nbOfTuples+1,1);
7919 int *cp=c->getPointer();
7920 int *cip=cI->getPointer();
7922 for(int i=0;i<nbOfTuples;i++)
7924 *cp++=INTERP_KERNEL::NORM_POINT1;
7928 ret->setConnectivity(c,cI,true);
7932 * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
7933 * Cells and nodes of
7934 * the first mesh precede cells and nodes of the second mesh within the result mesh.
7935 * \param [in] mesh1 - the first mesh.
7936 * \param [in] mesh2 - the second mesh.
7937 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7938 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7939 * is no more needed.
7940 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
7941 * \throw If the coordinates array is not set in none of the meshes.
7942 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
7943 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
7945 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
7947 std::vector<const MEDCouplingUMesh *> tmp(2);
7948 tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
7949 return MergeUMeshes(tmp);
7953 * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
7954 * Cells and nodes of
7955 * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
7956 * \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
7957 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7958 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7959 * is no more needed.
7960 * \throw If \a a.size() == 0.
7961 * \throw If \a a[ *i* ] == NULL.
7962 * \throw If the coordinates array is not set in none of the meshes.
7963 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
7964 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
7966 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const std::vector<const MEDCouplingUMesh *>& a)
7968 std::size_t sz=a.size();
7970 return MergeUMeshesLL(a);
7971 for(std::size_t ii=0;ii<sz;ii++)
7974 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
7975 throw INTERP_KERNEL::Exception(oss.str());
7977 std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
7978 std::vector< const MEDCouplingUMesh * > aa(sz);
7980 for(std::size_t i=0;i<sz && spaceDim==-3;i++)
7982 const MEDCouplingUMesh *cur=a[i];
7983 const DataArrayDouble *coo=cur->getCoords();
7985 spaceDim=coo->getNumberOfComponents();
7988 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
7989 for(std::size_t i=0;i<sz;i++)
7991 bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
7994 return MergeUMeshesLL(aa);
7999 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesLL(const std::vector<const MEDCouplingUMesh *>& a)
8002 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : input array must be NON EMPTY !");
8003 std::vector<const MEDCouplingUMesh *>::const_iterator it=a.begin();
8004 int meshDim=(*it)->getMeshDimension();
8005 int nbOfCells=(*it)->getNumberOfCells();
8006 int meshLgth=(*it++)->getNodalConnectivityArrayLen();
8007 for(;it!=a.end();it++)
8009 if(meshDim!=(*it)->getMeshDimension())
8010 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, MergeUMeshes impossible !");
8011 nbOfCells+=(*it)->getNumberOfCells();
8012 meshLgth+=(*it)->getNodalConnectivityArrayLen();
8014 std::vector<const MEDCouplingPointSet *> aps(a.size());
8015 std::copy(a.begin(),a.end(),aps.begin());
8016 MCAuto<DataArrayDouble> pts=MergeNodesArray(aps);
8017 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("merge",meshDim);
8018 ret->setCoords(pts);
8019 MCAuto<DataArrayInt> c=DataArrayInt::New();
8020 c->alloc(meshLgth,1);
8021 int *cPtr=c->getPointer();
8022 MCAuto<DataArrayInt> cI=DataArrayInt::New();
8023 cI->alloc(nbOfCells+1,1);
8024 int *cIPtr=cI->getPointer();
8028 for(it=a.begin();it!=a.end();it++)
8030 int curNbOfCell=(*it)->getNumberOfCells();
8031 const int *curCI=(*it)->_nodal_connec_index->getConstPointer();
8032 const int *curC=(*it)->_nodal_connec->getConstPointer();
8033 cIPtr=std::transform(curCI+1,curCI+curNbOfCell+1,cIPtr,std::bind2nd(std::plus<int>(),offset));
8034 for(int j=0;j<curNbOfCell;j++)
8036 const int *src=curC+curCI[j];
8038 for(;src!=curC+curCI[j+1];src++,cPtr++)
8046 offset+=curCI[curNbOfCell];
8047 offset2+=(*it)->getNumberOfNodes();
8050 ret->setConnectivity(c,cI,true);
8057 * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
8058 * dimension and sharing the node coordinates array.
8059 * All cells of the first mesh precede all cells of the second mesh
8060 * within the result mesh.
8061 * \param [in] mesh1 - the first mesh.
8062 * \param [in] mesh2 - the second mesh.
8063 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8064 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8065 * is no more needed.
8066 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
8067 * \throw If the meshes do not share the node coordinates array.
8068 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
8069 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
8071 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
8073 std::vector<const MEDCouplingUMesh *> tmp(2);
8074 tmp[0]=mesh1; tmp[1]=mesh2;
8075 return MergeUMeshesOnSameCoords(tmp);
8079 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
8080 * dimension and sharing the node coordinates array.
8081 * All cells of the *i*-th mesh precede all cells of the
8082 * (*i*+1)-th mesh within the result mesh.
8083 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
8084 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8085 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8086 * is no more needed.
8087 * \throw If \a a.size() == 0.
8088 * \throw If \a a[ *i* ] == NULL.
8089 * \throw If the meshes do not share the node coordinates array.
8090 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
8091 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
8093 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
8096 throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
8097 for(std::size_t ii=0;ii<meshes.size();ii++)
8100 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
8101 throw INTERP_KERNEL::Exception(oss.str());
8103 const DataArrayDouble *coords=meshes.front()->getCoords();
8104 int meshDim=meshes.front()->getMeshDimension();
8105 std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
8107 int meshIndexLgth=0;
8108 for(;iter!=meshes.end();iter++)
8110 if(coords!=(*iter)->getCoords())
8111 throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
8112 if(meshDim!=(*iter)->getMeshDimension())
8113 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
8114 meshLgth+=(*iter)->getNodalConnectivityArrayLen();
8115 meshIndexLgth+=(*iter)->getNumberOfCells();
8117 MCAuto<DataArrayInt> nodal=DataArrayInt::New();
8118 nodal->alloc(meshLgth,1);
8119 int *nodalPtr=nodal->getPointer();
8120 MCAuto<DataArrayInt> nodalIndex=DataArrayInt::New();
8121 nodalIndex->alloc(meshIndexLgth+1,1);
8122 int *nodalIndexPtr=nodalIndex->getPointer();
8124 for(iter=meshes.begin();iter!=meshes.end();iter++)
8126 const int *nod=(*iter)->getNodalConnectivity()->getConstPointer();
8127 const int *index=(*iter)->getNodalConnectivityIndex()->getConstPointer();
8128 int nbOfCells=(*iter)->getNumberOfCells();
8129 int meshLgth2=(*iter)->getNodalConnectivityArrayLen();
8130 nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
8131 if(iter!=meshes.begin())
8132 nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind2nd(std::plus<int>(),offset));
8134 nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
8137 MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
8138 ret->setName("merge");
8139 ret->setMeshDimension(meshDim);
8140 ret->setConnectivity(nodal,nodalIndex,true);
8141 ret->setCoords(coords);
8146 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
8147 * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
8148 * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
8149 * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
8150 * New" mode are returned for each input mesh.
8151 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
8152 * \param [in] compType - specifies a cell comparison technique. For meaning of its
8153 * valid values [0,1,2], see zipConnectivityTraducer().
8154 * \param [in,out] corr - an array of DataArrayInt, of the same size as \a
8155 * meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
8156 * mesh. The caller is to delete each of the arrays using decrRef() as it is
8158 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8159 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8160 * is no more needed.
8161 * \throw If \a meshes.size() == 0.
8162 * \throw If \a meshes[ *i* ] == NULL.
8163 * \throw If the meshes do not share the node coordinates array.
8164 * \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
8165 * \throw If the \a meshes are of different dimension (getMeshDimension()).
8166 * \throw If the nodal connectivity of cells of any of \a meshes is not defined.
8167 * \throw If the nodal connectivity any of \a meshes includes an invalid id.
8169 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayInt *>& corr)
8171 //All checks are delegated to MergeUMeshesOnSameCoords
8172 MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
8173 MCAuto<DataArrayInt> o2n=ret->zipConnectivityTraducer(compType);
8174 corr.resize(meshes.size());
8175 std::size_t nbOfMeshes=meshes.size();
8177 const int *o2nPtr=o2n->getConstPointer();
8178 for(std::size_t i=0;i<nbOfMeshes;i++)
8180 DataArrayInt *tmp=DataArrayInt::New();
8181 int curNbOfCells=meshes[i]->getNumberOfCells();
8182 tmp->alloc(curNbOfCells,1);
8183 std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
8184 offset+=curNbOfCells;
8185 tmp->setName(meshes[i]->getName());
8192 * Makes all given meshes share the nodal connectivity array. The common connectivity
8193 * array is created by concatenating the connectivity arrays of all given meshes. All
8194 * the given meshes must be of the same space dimension but dimension of cells **can
8195 * differ**. This method is particulary useful in MEDLoader context to build a \ref
8196 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
8197 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
8198 * \param [in,out] meshes - a vector of meshes to update.
8199 * \throw If any of \a meshes is NULL.
8200 * \throw If the coordinates array is not set in any of \a meshes.
8201 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
8202 * \throw If \a meshes are of different space dimension.
8204 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
8206 std::size_t sz=meshes.size();
8209 std::vector< const DataArrayDouble * > coords(meshes.size());
8210 std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
8211 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
8215 (*it)->checkConnectivityFullyDefined();
8216 const DataArrayDouble *coo=(*it)->getCoords();
8221 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
8222 oss << " has no coordinate array defined !";
8223 throw INTERP_KERNEL::Exception(oss.str());
8228 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
8229 oss << " is null !";
8230 throw INTERP_KERNEL::Exception(oss.str());
8233 MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
8234 std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
8235 int offset=(*it)->getNumberOfNodes();
8236 (*it++)->setCoords(res);
8237 for(;it!=meshes.end();it++)
8239 int oldNumberOfNodes=(*it)->getNumberOfNodes();
8240 (*it)->setCoords(res);
8241 (*it)->shiftNodeNumbersInConn(offset);
8242 offset+=oldNumberOfNodes;
8247 * Merges nodes coincident with a given precision within all given meshes that share
8248 * the nodal connectivity array. The given meshes **can be of different** mesh
8249 * dimension. This method is particulary useful in MEDLoader context to build a \ref
8250 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
8251 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
8252 * \param [in,out] meshes - a vector of meshes to update.
8253 * \param [in] eps - the precision used to detect coincident nodes (infinite norm).
8254 * \throw If any of \a meshes is NULL.
8255 * \throw If the \a meshes do not share the same node coordinates array.
8256 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
8258 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
8262 std::set<const DataArrayDouble *> s;
8263 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
8266 s.insert((*it)->getCoords());
8269 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 !";
8270 throw INTERP_KERNEL::Exception(oss.str());
8275 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 !";
8276 throw INTERP_KERNEL::Exception(oss.str());
8278 const DataArrayDouble *coo=*(s.begin());
8282 DataArrayInt *comm,*commI;
8283 coo->findCommonTuples(eps,-1,comm,commI);
8284 MCAuto<DataArrayInt> tmp1(comm),tmp2(commI);
8285 int oldNbOfNodes=coo->getNumberOfTuples();
8287 MCAuto<DataArrayInt> o2n=DataArrayInt::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
8288 if(oldNbOfNodes==newNbOfNodes)
8290 MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->getConstPointer(),newNbOfNodes);
8291 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
8293 (*it)->renumberNodesInConn(o2n->getConstPointer());
8294 (*it)->setCoords(newCoords);
8299 * 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.
8300 * \param nbOfNodesPerLev in parameter that specifies the number of nodes of one slice of global dataset
8301 * \param isQuad specifies the policy of connectivity.
8302 * @ret in/out parameter in which the result will be append
8304 void MEDCouplingUMesh::AppendExtrudedCell(const int *connBg, const int *connEnd, int nbOfNodesPerLev, bool isQuad, std::vector<int>& ret)
8306 INTERP_KERNEL::NormalizedCellType flatType=(INTERP_KERNEL::NormalizedCellType)connBg[0];
8307 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(flatType);
8308 ret.push_back(cm.getExtrudedType());
8309 int deltaz=isQuad?2*nbOfNodesPerLev:nbOfNodesPerLev;
8312 case INTERP_KERNEL::NORM_POINT1:
8314 ret.push_back(connBg[1]);
8315 ret.push_back(connBg[1]+nbOfNodesPerLev);
8318 case INTERP_KERNEL::NORM_SEG2:
8320 int conn[4]={connBg[1],connBg[2],connBg[2]+deltaz,connBg[1]+deltaz};
8321 ret.insert(ret.end(),conn,conn+4);
8324 case INTERP_KERNEL::NORM_SEG3:
8326 int conn[8]={connBg[1],connBg[3],connBg[3]+deltaz,connBg[1]+deltaz,connBg[2],connBg[3]+nbOfNodesPerLev,connBg[2]+deltaz,connBg[1]+nbOfNodesPerLev};
8327 ret.insert(ret.end(),conn,conn+8);
8330 case INTERP_KERNEL::NORM_QUAD4:
8332 int conn[8]={connBg[1],connBg[2],connBg[3],connBg[4],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4]+deltaz};
8333 ret.insert(ret.end(),conn,conn+8);
8336 case INTERP_KERNEL::NORM_TRI3:
8338 int conn[6]={connBg[1],connBg[2],connBg[3],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz};
8339 ret.insert(ret.end(),conn,conn+6);
8342 case INTERP_KERNEL::NORM_TRI6:
8344 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,
8345 connBg[1]+nbOfNodesPerLev,connBg[2]+nbOfNodesPerLev,connBg[3]+nbOfNodesPerLev};
8346 ret.insert(ret.end(),conn,conn+15);
8349 case INTERP_KERNEL::NORM_QUAD8:
8352 connBg[1],connBg[2],connBg[3],connBg[4],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4]+deltaz,
8353 connBg[5],connBg[6],connBg[7],connBg[8],connBg[5]+deltaz,connBg[6]+deltaz,connBg[7]+deltaz,connBg[8]+deltaz,
8354 connBg[1]+nbOfNodesPerLev,connBg[2]+nbOfNodesPerLev,connBg[3]+nbOfNodesPerLev,connBg[4]+nbOfNodesPerLev
8356 ret.insert(ret.end(),conn,conn+20);
8359 case INTERP_KERNEL::NORM_POLYGON:
8361 std::back_insert_iterator< std::vector<int> > ii(ret);
8362 std::copy(connBg+1,connEnd,ii);
8364 std::reverse_iterator<const int *> rConnBg(connEnd);
8365 std::reverse_iterator<const int *> rConnEnd(connBg+1);
8366 std::transform(rConnBg,rConnEnd,ii,std::bind2nd(std::plus<int>(),deltaz));
8367 std::size_t nbOfRadFaces=std::distance(connBg+1,connEnd);
8368 for(std::size_t i=0;i<nbOfRadFaces;i++)
8371 int conn[4]={connBg[(i+1)%nbOfRadFaces+1],connBg[i+1],connBg[i+1]+deltaz,connBg[(i+1)%nbOfRadFaces+1]+deltaz};
8372 std::copy(conn,conn+4,ii);
8377 throw INTERP_KERNEL::Exception("A flat type has been detected that has not its extruded representation !");
8382 * This static operates only for coords in 3D. The polygon is specfied by its connectivity nodes in [ \a begin , \a end ).
8384 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const int *begin, const int *end, const double *coords)
8387 double v[3]={0.,0.,0.};
8388 std::size_t sz=std::distance(begin,end);
8393 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];
8394 v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
8395 v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
8397 double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
8399 // Try using quadratic points if standard points are degenerated (for example a QPOLYG with two
8400 // SEG3 forming a circle):
8401 if (fabs(ret) < INTERP_KERNEL::DEFAULT_ABS_TOL && isQuadratic)
8403 v[0] = 0.0; v[1] = 0.0; v[2] = 0.0;
8404 for(std::size_t j=0;j<sz;j++)
8406 if (j%2) // current point i is quadratic, next point i+1 is standard
8409 ip1 = (j+1)%sz; // ip1 = "i+1"
8411 else // current point i is standard, next point i+1 is quadratic
8416 v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
8417 v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
8418 v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
8420 ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
8426 * The polyhedron is specfied by its connectivity nodes in [ \a begin , \a end ).
8428 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const int *begin, const int *end, const double *coords)
8430 std::vector<std::pair<int,int> > edges;
8431 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
8432 const int *bgFace=begin;
8433 for(std::size_t i=0;i<nbOfFaces;i++)
8435 const int *endFace=std::find(bgFace+1,end,-1);
8436 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
8437 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8439 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8440 if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
8442 edges.push_back(p1);
8446 return INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)>-EPS_FOR_POLYH_ORIENTATION;
8450 * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
8452 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const int *begin, const int *end, const double *coords)
8454 double vec0[3],vec1[3];
8455 std::size_t sz=std::distance(begin,end);
8457 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
8458 int nbOfNodes=(int)sz/2;
8459 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
8460 const double *pt0=coords+3*begin[0];
8461 const double *pt1=coords+3*begin[nbOfNodes];
8462 vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
8463 return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
8466 void MEDCouplingUMesh::CorrectExtrudedStaticCell(int *begin, int *end)
8468 std::size_t sz=std::distance(begin,end);
8469 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
8470 std::size_t nbOfNodes(sz/2);
8471 std::copy(begin,end,(int *)tmp);
8472 for(std::size_t j=1;j<nbOfNodes;j++)
8474 begin[j]=tmp[nbOfNodes-j];
8475 begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
8479 bool MEDCouplingUMesh::IsTetra4WellOriented(const int *begin, const int *end, const double *coords)
8481 std::size_t sz=std::distance(begin,end);
8483 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
8484 double vec0[3],vec1[3];
8485 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
8486 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];
8487 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;
8490 bool MEDCouplingUMesh::IsPyra5WellOriented(const int *begin, const int *end, const double *coords)
8492 std::size_t sz=std::distance(begin,end);
8494 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
8496 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
8497 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
8498 return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
8502 * 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 )
8503 * 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
8506 * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
8507 * \param [in] coords the coordinates with nb of components exactly equal to 3
8508 * \param [in] begin begin of the nodal connectivity (geometric type included) of a single polyhedron cell
8509 * \param [in] end end of nodal connectivity of a single polyhedron cell (excluded)
8510 * \param [out] res the result is put at the end of the vector without any alteration of the data.
8512 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, const int *begin, const int *end, DataArrayInt *res)
8514 int nbFaces=std::count(begin+1,end,-1)+1;
8515 MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
8516 double *vPtr=v->getPointer();
8517 MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,1);
8518 double *pPtr=p->getPointer();
8519 const int *stFaceConn=begin+1;
8520 for(int i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
8522 const int *endFaceConn=std::find(stFaceConn,end,-1);
8523 ComputeVecAndPtOfFace(eps,coords->getConstPointer(),stFaceConn,endFaceConn,vPtr,pPtr);
8524 stFaceConn=endFaceConn+1;
8526 pPtr=p->getPointer(); vPtr=v->getPointer();
8527 DataArrayInt *comm1=0,*commI1=0;
8528 v->findCommonTuples(eps,-1,comm1,commI1);
8529 MCAuto<DataArrayInt> comm1Auto(comm1),commI1Auto(commI1);
8530 const int *comm1Ptr=comm1->getConstPointer();
8531 const int *commI1Ptr=commI1->getConstPointer();
8532 int nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
8533 res->pushBackSilent((int)INTERP_KERNEL::NORM_POLYHED);
8535 MCAuto<MEDCouplingUMesh> mm=MEDCouplingUMesh::New("",3);
8536 mm->setCoords(const_cast<DataArrayDouble *>(coords)); mm->allocateCells(1); mm->insertNextCell(INTERP_KERNEL::NORM_POLYHED,(int)std::distance(begin+1,end),begin+1);
8537 mm->finishInsertingCells();
8539 for(int i=0;i<nbOfGrps1;i++)
8541 int vecId=comm1Ptr[commI1Ptr[i]];
8542 MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
8543 DataArrayInt *comm2=0,*commI2=0;
8544 tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
8545 MCAuto<DataArrayInt> comm2Auto(comm2),commI2Auto(commI2);
8546 const int *comm2Ptr=comm2->getConstPointer();
8547 const int *commI2Ptr=commI2->getConstPointer();
8548 int nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
8549 for(int j=0;j<nbOfGrps2;j++)
8551 if(commI2Ptr[j+1]-commI2Ptr[j]<=1)
8553 res->insertAtTheEnd(begin,end);
8554 res->pushBackSilent(-1);
8558 int pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
8559 MCAuto<DataArrayInt> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
8560 ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
8561 DataArrayInt *tmp0=DataArrayInt::New(),*tmp1=DataArrayInt::New(),*tmp2=DataArrayInt::New(),*tmp3=DataArrayInt::New();
8562 MCAuto<MEDCouplingUMesh> mm2=mm->buildDescendingConnectivity(tmp0,tmp1,tmp2,tmp3); tmp0->decrRef(); tmp1->decrRef(); tmp2->decrRef(); tmp3->decrRef();
8563 MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(mm2->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
8564 MCAuto<DataArrayInt> idsNodeTmp=mm3->zipCoordsTraducer();
8565 MCAuto<DataArrayInt> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
8566 const int *idsNodePtr=idsNode->getConstPointer();
8567 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];
8568 double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
8569 double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
8570 if(std::abs(norm)>eps)
8572 double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
8573 mm3->rotate(center,vec,angle);
8575 mm3->changeSpaceDimension(2);
8576 MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
8577 const int *conn4=mm4->getNodalConnectivity()->getConstPointer();
8578 const int *connI4=mm4->getNodalConnectivityIndex()->getConstPointer();
8579 int nbOfCells=mm4->getNumberOfCells();
8580 for(int k=0;k<nbOfCells;k++)
8583 for(const int *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
8584 res->pushBackSilent(idsNodePtr[*work]);
8585 res->pushBackSilent(-1);
8590 res->popBackSilent();
8594 * 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
8595 * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
8597 * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
8598 * \param [in] coords coordinates expected to have 3 components.
8599 * \param [in] begin start of the nodal connectivity of the face.
8600 * \param [in] end end of the nodal connectivity (excluded) of the face.
8601 * \param [out] v the normalized vector of size 3
8602 * \param [out] p the pos of plane
8604 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const int *begin, const int *end, double *v, double *p)
8606 std::size_t nbPoints=std::distance(begin,end);
8608 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
8609 double vec[3]={0.,0.,0.};
8611 bool refFound=false;
8612 for(;j<nbPoints-1 && !refFound;j++)
8614 vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
8615 vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
8616 vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
8617 double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
8621 vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
8624 for(std::size_t i=j;i<nbPoints-1;i++)
8627 curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
8628 curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
8629 curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
8630 double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
8633 curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
8634 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];
8635 norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
8638 v[0]/=norm; v[1]/=norm; v[2]/=norm;
8639 *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
8643 throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
8647 * This method tries to obtain a well oriented polyhedron.
8648 * If the algorithm fails, an exception will be thrown.
8650 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(int *begin, int *end, const double *coords)
8652 std::list< std::pair<int,int> > edgesOK,edgesFinished;
8653 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
8654 std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
8656 int *bgFace=begin,*endFace=std::find(begin+1,end,-1);
8657 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
8658 for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<int,int> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
8660 while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
8663 std::size_t smthChanged=0;
8664 for(std::size_t i=0;i<nbOfFaces;i++)
8666 endFace=std::find(bgFace+1,end,-1);
8667 nbOfEdgesInFace=std::distance(bgFace,endFace);
8671 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8673 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8674 std::pair<int,int> p2(p1.second,p1.first);
8675 bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
8676 bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
8677 if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
8682 std::reverse(bgFace+1,endFace);
8683 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8685 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8686 std::pair<int,int> p2(p1.second,p1.first);
8687 if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
8688 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
8689 if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
8690 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
8691 std::list< std::pair<int,int> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
8692 if(it!=edgesOK.end())
8695 edgesFinished.push_back(p1);
8698 edgesOK.push_back(p1);
8705 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
8707 if(!edgesOK.empty())
8708 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
8709 if(INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)<-EPS_FOR_POLYH_ORIENTATION)
8710 {//not lucky ! The first face was not correctly oriented : reorient all faces...
8712 for(std::size_t i=0;i<nbOfFaces;i++)
8714 endFace=std::find(bgFace+1,end,-1);
8715 std::reverse(bgFace+1,endFace);
8721 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMeshLinear(const MEDCouplingUMesh *skin, const DataArrayInt *n2o) const
8723 int nbOfNodesExpected(skin->getNumberOfNodes());
8724 const int *n2oPtr(n2o->getConstPointer());
8725 MCAuto<DataArrayInt> revNodal(DataArrayInt::New()),revNodalI(DataArrayInt::New());
8726 skin->getReverseNodalConnectivity(revNodal,revNodalI);
8727 const int *revNodalPtr(revNodal->getConstPointer()),*revNodalIPtr(revNodalI->getConstPointer());
8728 const int *nodalPtr(skin->getNodalConnectivity()->getConstPointer());
8729 const int *nodalIPtr(skin->getNodalConnectivityIndex()->getConstPointer());
8730 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfNodesExpected+1,1);
8731 int *work(ret->getPointer()); *work++=INTERP_KERNEL::NORM_POLYGON;
8732 if(nbOfNodesExpected<1)
8734 int prevCell(0),prevNode(nodalPtr[nodalIPtr[0]+1]);
8735 *work++=n2oPtr[prevNode];
8736 for(int i=1;i<nbOfNodesExpected;i++)
8738 if(nodalIPtr[prevCell+1]-nodalIPtr[prevCell]==3)
8740 std::set<int> conn(nodalPtr+nodalIPtr[prevCell]+1,nodalPtr+nodalIPtr[prevCell]+3);
8741 conn.erase(prevNode);
8744 int curNode(*(conn.begin()));
8745 *work++=n2oPtr[curNode];
8746 std::set<int> shar(revNodalPtr+revNodalIPtr[curNode],revNodalPtr+revNodalIPtr[curNode+1]);
8747 shar.erase(prevCell);
8750 prevCell=*(shar.begin());
8754 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected 2 !");
8757 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected 1 !");
8760 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected cell !");
8765 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMeshQuadratic(const MEDCouplingUMesh *skin, const DataArrayInt *n2o) const
8767 int nbOfNodesExpected(skin->getNumberOfNodes());
8768 int nbOfTurn(nbOfNodesExpected/2);
8769 const int *n2oPtr(n2o->getConstPointer());
8770 MCAuto<DataArrayInt> revNodal(DataArrayInt::New()),revNodalI(DataArrayInt::New());
8771 skin->getReverseNodalConnectivity(revNodal,revNodalI);
8772 const int *revNodalPtr(revNodal->getConstPointer()),*revNodalIPtr(revNodalI->getConstPointer());
8773 const int *nodalPtr(skin->getNodalConnectivity()->getConstPointer());
8774 const int *nodalIPtr(skin->getNodalConnectivityIndex()->getConstPointer());
8775 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfNodesExpected+1,1);
8776 int *work(ret->getPointer()); *work++=INTERP_KERNEL::NORM_QPOLYG;
8777 if(nbOfNodesExpected<1)
8779 int prevCell(0),prevNode(nodalPtr[nodalIPtr[0]+1]);
8780 *work=n2oPtr[prevNode]; work[nbOfTurn]=n2oPtr[nodalPtr[nodalIPtr[0]+3]]; work++;
8781 for(int i=1;i<nbOfTurn;i++)
8783 if(nodalIPtr[prevCell+1]-nodalIPtr[prevCell]==4)
8785 std::set<int> conn(nodalPtr+nodalIPtr[prevCell]+1,nodalPtr+nodalIPtr[prevCell]+3);
8786 conn.erase(prevNode);
8789 int curNode(*(conn.begin()));
8790 *work=n2oPtr[curNode];
8791 std::set<int> shar(revNodalPtr+revNodalIPtr[curNode],revNodalPtr+revNodalIPtr[curNode+1]);
8792 shar.erase(prevCell);
8795 int curCell(*(shar.begin()));
8796 work[nbOfTurn]=n2oPtr[nodalPtr[nodalIPtr[curCell]+3]];
8802 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected 2 !");
8805 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected 1 !");
8808 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected cell !");
8814 * This method makes the assumption spacedimension == meshdimension == 2.
8815 * This method works only for linear cells.
8817 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
8819 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMesh() const
8821 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
8822 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
8823 MCAuto<MEDCouplingUMesh> skin(computeSkin());
8824 int oldNbOfNodes(skin->getNumberOfNodes());
8825 MCAuto<DataArrayInt> o2n(skin->zipCoordsTraducer());
8826 int nbOfNodesExpected(skin->getNumberOfNodes());
8827 MCAuto<DataArrayInt> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
8828 int nbCells(skin->getNumberOfCells());
8829 if(nbCells==nbOfNodesExpected)
8830 return buildUnionOf2DMeshLinear(skin,n2o);
8831 else if(2*nbCells==nbOfNodesExpected)
8832 return buildUnionOf2DMeshQuadratic(skin,n2o);
8834 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
8838 * This method makes the assumption spacedimension == meshdimension == 3.
8839 * This method works only for linear cells.
8841 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
8843 DataArrayInt *MEDCouplingUMesh::buildUnionOf3DMesh() const
8845 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8846 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
8847 MCAuto<MEDCouplingUMesh> m=computeSkin();
8848 const int *conn=m->getNodalConnectivity()->getConstPointer();
8849 const int *connI=m->getNodalConnectivityIndex()->getConstPointer();
8850 int nbOfCells=m->getNumberOfCells();
8851 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
8852 int *work=ret->getPointer(); *work++=INTERP_KERNEL::NORM_POLYHED;
8855 work=std::copy(conn+connI[0]+1,conn+connI[1],work);
8856 for(int i=1;i<nbOfCells;i++)
8859 work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
8865 * \brief Creates a graph of cell neighbors
8866 * \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
8867 * In the sky line array, graph arcs are stored in terms of (index,value) notation.
8869 * - index: 0 3 5 6 6
8870 * - value: 1 2 3 2 3 3
8871 * means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
8872 * Arcs are not doubled but reflexive (1,1) arcs are present for each cell
8874 MEDCouplingSkyLineArray *MEDCouplingUMesh::generateGraph() const
8876 checkConnectivityFullyDefined();
8878 int meshDim = this->getMeshDimension();
8879 MEDCoupling::DataArrayInt* indexr=MEDCoupling::DataArrayInt::New();
8880 MEDCoupling::DataArrayInt* revConn=MEDCoupling::DataArrayInt::New();
8881 this->getReverseNodalConnectivity(revConn,indexr);
8882 const int* indexr_ptr=indexr->getConstPointer();
8883 const int* revConn_ptr=revConn->getConstPointer();
8885 const MEDCoupling::DataArrayInt* index;
8886 const MEDCoupling::DataArrayInt* conn;
8887 conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
8888 index=this->getNodalConnectivityIndex();
8889 int nbCells=this->getNumberOfCells();
8890 const int* index_ptr=index->getConstPointer();
8891 const int* conn_ptr=conn->getConstPointer();
8893 //creating graph arcs (cell to cell relations)
8894 //arcs are stored in terms of (index,value) notation
8897 // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
8898 // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
8900 //warning here one node have less than or equal effective number of cell with it
8901 //but cell could have more than effective nodes
8902 //because other equals nodes in other domain (with other global inode)
8903 std::vector <int> cell2cell_index(nbCells+1,0);
8904 std::vector <int> cell2cell;
8905 cell2cell.reserve(3*nbCells);
8907 for (int icell=0; icell<nbCells;icell++)
8909 std::map<int,int > counter;
8910 for (int iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
8912 int inode=conn_ptr[iconn];
8913 for (int iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
8915 int icell2=revConn_ptr[iconnr];
8916 std::map<int,int>::iterator iter=counter.find(icell2);
8917 if (iter!=counter.end()) (iter->second)++;
8918 else counter.insert(std::make_pair(icell2,1));
8921 for (std::map<int,int>::const_iterator iter=counter.begin();
8922 iter!=counter.end(); iter++)
8923 if (iter->second >= meshDim)
8925 cell2cell_index[icell+1]++;
8926 cell2cell.push_back(iter->first);
8931 cell2cell_index[0]=0;
8932 for (int icell=0; icell<nbCells;icell++)
8933 cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
8935 //filling up index and value to create skylinearray structure
8936 MEDCouplingSkyLineArray* array=new MEDCouplingSkyLineArray(cell2cell_index,cell2cell);
8941 * This method put in zip format into parameter 'zipFrmt' in full interlace mode.
8942 * This format is often asked by INTERP_KERNEL algorithms to avoid many indirections into coordinates array.
8944 void MEDCouplingUMesh::FillInCompact3DMode(int spaceDim, int nbOfNodesInCell, const int *conn, const double *coo, double *zipFrmt)
8948 for(int i=0;i<nbOfNodesInCell;i++)
8949 w=std::copy(coo+3*conn[i],coo+3*conn[i]+3,w);
8950 else if(spaceDim==2)
8952 for(int i=0;i<nbOfNodesInCell;i++)
8954 w=std::copy(coo+2*conn[i],coo+2*conn[i]+2,w);
8959 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::FillInCompact3DMode : Invalid spaceDim specified : must be 2 or 3 !");
8962 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
8964 int nbOfCells=getNumberOfCells();
8966 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
8967 ofs << " <" << getVTKDataSetType() << ">\n";
8968 ofs << " <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
8969 ofs << " <PointData>\n" << pointData << std::endl;
8970 ofs << " </PointData>\n";
8971 ofs << " <CellData>\n" << cellData << std::endl;
8972 ofs << " </CellData>\n";
8973 ofs << " <Points>\n";
8974 if(getSpaceDimension()==3)
8975 _coords->writeVTK(ofs,8,"Points",byteData);
8978 MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
8979 coo->writeVTK(ofs,8,"Points",byteData);
8981 ofs << " </Points>\n";
8982 ofs << " <Cells>\n";
8983 const int *cPtr=_nodal_connec->getConstPointer();
8984 const int *cIPtr=_nodal_connec_index->getConstPointer();
8985 MCAuto<DataArrayInt> faceoffsets=DataArrayInt::New(); faceoffsets->alloc(nbOfCells,1);
8986 MCAuto<DataArrayInt> types=DataArrayInt::New(); types->alloc(nbOfCells,1);
8987 MCAuto<DataArrayInt> offsets=DataArrayInt::New(); offsets->alloc(nbOfCells,1);
8988 MCAuto<DataArrayInt> connectivity=DataArrayInt::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
8989 int *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
8990 int szFaceOffsets=0,szConn=0;
8991 for(int i=0;i<nbOfCells;i++,w1++,w2++,w3++)
8994 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
8997 *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
8998 w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
9002 int deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
9003 *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
9004 std::set<int> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
9005 *w3=szConn+(int)c.size(); szConn+=(int)c.size();
9006 w4=std::copy(c.begin(),c.end(),w4);
9009 types->transformWithIndArr(MEDCOUPLING2VTKTYPETRADUCER,MEDCOUPLING2VTKTYPETRADUCER+INTERP_KERNEL::NORM_MAXTYPE+1);
9010 types->writeVTK(ofs,8,"UInt8","types",byteData);
9011 offsets->writeVTK(ofs,8,"Int32","offsets",byteData);
9012 if(szFaceOffsets!=0)
9013 {//presence of Polyhedra
9014 connectivity->reAlloc(szConn);
9015 faceoffsets->writeVTK(ofs,8,"Int32","faceoffsets",byteData);
9016 MCAuto<DataArrayInt> faces=DataArrayInt::New(); faces->alloc(szFaceOffsets,1);
9017 w1=faces->getPointer();
9018 for(int i=0;i<nbOfCells;i++)
9019 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
9021 int nbFaces=std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1)+1;
9023 const int *w6=cPtr+cIPtr[i]+1,*w5=0;
9024 for(int j=0;j<nbFaces;j++)
9026 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
9027 *w1++=(int)std::distance(w6,w5);
9028 w1=std::copy(w6,w5,w1);
9032 faces->writeVTK(ofs,8,"Int32","faces",byteData);
9034 connectivity->writeVTK(ofs,8,"Int32","connectivity",byteData);
9035 ofs << " </Cells>\n";
9036 ofs << " </Piece>\n";
9037 ofs << " </" << getVTKDataSetType() << ">\n";
9040 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
9042 stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
9044 { stream << " Not set !"; return ; }
9045 stream << " Mesh dimension : " << _mesh_dim << ".";
9049 { stream << " No coordinates set !"; return ; }
9050 if(!_coords->isAllocated())
9051 { stream << " Coordinates set but not allocated !"; return ; }
9052 stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
9053 stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
9054 if(!_nodal_connec_index)
9055 { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
9056 if(!_nodal_connec_index->isAllocated())
9057 { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
9058 int lgth=_nodal_connec_index->getNumberOfTuples();
9059 int cpt=_nodal_connec_index->getNumberOfComponents();
9060 if(cpt!=1 || lgth<1)
9062 stream << std::endl << "Number of cells : " << lgth-1 << ".";
9065 std::string MEDCouplingUMesh::getVTKDataSetType() const
9067 return std::string("UnstructuredGrid");
9070 std::string MEDCouplingUMesh::getVTKFileExtension() const
9072 return std::string("vtu");
9076 * Partitions the first given 2D mesh using the second given 2D mesh as a tool, and
9077 * returns a result mesh constituted by polygons.
9078 * Thus the final result contains all nodes from m1 plus new nodes. However it doesn't necessarily contains
9079 * all nodes from m2.
9080 * The meshes should be in 2D space. In
9081 * addition, returns two arrays mapping cells of the result mesh to cells of the input
9083 * \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
9084 * 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)
9085 * \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
9086 * 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)
9087 * \param [in] eps - precision used to detect coincident mesh entities.
9088 * \param [out] cellNb1 - a new instance of DataArrayInt holding for each result
9089 * cell an id of the cell of \a m1 it comes from. The caller is to delete
9090 * this array using decrRef() as it is no more needed.
9091 * \param [out] cellNb2 - a new instance of DataArrayInt holding for each result
9092 * cell an id of the cell of \a m2 it comes from. -1 value means that a
9093 * result cell comes from a cell (or part of cell) of \a m1 not overlapped by
9094 * any cell of \a m2. The caller is to delete this array using decrRef() as
9095 * it is no more needed.
9096 * \return MEDCouplingUMesh * - the result 2D mesh which is a new instance of
9097 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
9098 * is no more needed.
9099 * \throw If the coordinates array is not set in any of the meshes.
9100 * \throw If the nodal connectivity of cells is not defined in any of the meshes.
9101 * \throw If any of the meshes is not a 2D mesh in 2D space.
9103 * \sa conformize2D, mergeNodes
9105 MEDCouplingUMesh *MEDCouplingUMesh::Intersect2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2,
9106 double eps, DataArrayInt *&cellNb1, DataArrayInt *&cellNb2)
9109 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshes : input meshes must be not NULL !");
9110 m1->checkFullyDefined();
9111 m2->checkFullyDefined();
9112 if(m1->getMeshDimension()!=2 || m1->getSpaceDimension()!=2 || m2->getMeshDimension()!=2 || m2->getSpaceDimension()!=2)
9113 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshes works on umeshes m1 AND m2 with meshdim equal to 2 and spaceDim equal to 2 too!");
9115 // Step 1: compute all edge intersections (new nodes)
9116 std::vector< std::vector<int> > intersectEdge1, colinear2, subDiv2;
9117 MEDCouplingUMesh *m1Desc=0,*m2Desc=0; // descending connec. meshes
9118 DataArrayInt *desc1=0,*descIndx1=0,*revDesc1=0,*revDescIndx1=0,*desc2=0,*descIndx2=0,*revDesc2=0,*revDescIndx2=0;
9119 std::vector<double> addCoo,addCoordsQuadratic; // coordinates of newly created nodes
9120 IntersectDescending2DMeshes(m1,m2,eps,intersectEdge1,colinear2, subDiv2,
9121 m1Desc,desc1,descIndx1,revDesc1,revDescIndx1,
9122 addCoo, m2Desc,desc2,descIndx2,revDesc2,revDescIndx2);
9123 revDesc1->decrRef(); revDescIndx1->decrRef(); revDesc2->decrRef(); revDescIndx2->decrRef();
9124 MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(desc2),dd4(descIndx2);
9125 MCAuto<MEDCouplingUMesh> dd5(m1Desc),dd6(m2Desc);
9127 // Step 2: re-order newly created nodes according to the ordering found in m2
9128 std::vector< std::vector<int> > intersectEdge2;
9129 BuildIntersectEdges(m1Desc,m2Desc,addCoo,subDiv2,intersectEdge2);
9130 subDiv2.clear(); dd5=0; dd6=0;
9133 std::vector<int> cr,crI; //no DataArrayInt because interface with Geometric2D
9134 std::vector<int> cNb1,cNb2; //no DataArrayInt because interface with Geometric2D
9135 BuildIntersecting2DCellsFromEdges(eps,m1,desc1->getConstPointer(),descIndx1->getConstPointer(),intersectEdge1,colinear2,m2,desc2->getConstPointer(),descIndx2->getConstPointer(),intersectEdge2,addCoo,
9136 /* outputs -> */addCoordsQuadratic,cr,crI,cNb1,cNb2);
9138 // Step 4: Prepare final result:
9139 MCAuto<DataArrayDouble> addCooDa(DataArrayDouble::New());
9140 addCooDa->alloc((int)(addCoo.size())/2,2);
9141 std::copy(addCoo.begin(),addCoo.end(),addCooDa->getPointer());
9142 MCAuto<DataArrayDouble> addCoordsQuadraticDa(DataArrayDouble::New());
9143 addCoordsQuadraticDa->alloc((int)(addCoordsQuadratic.size())/2,2);
9144 std::copy(addCoordsQuadratic.begin(),addCoordsQuadratic.end(),addCoordsQuadraticDa->getPointer());
9145 std::vector<const DataArrayDouble *> coordss(4);
9146 coordss[0]=m1->getCoords(); coordss[1]=m2->getCoords(); coordss[2]=addCooDa; coordss[3]=addCoordsQuadraticDa;
9147 MCAuto<DataArrayDouble> coo(DataArrayDouble::Aggregate(coordss));
9148 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("Intersect2D",2));
9149 MCAuto<DataArrayInt> conn(DataArrayInt::New()); conn->alloc((int)cr.size(),1); std::copy(cr.begin(),cr.end(),conn->getPointer());
9150 MCAuto<DataArrayInt> connI(DataArrayInt::New()); connI->alloc((int)crI.size(),1); std::copy(crI.begin(),crI.end(),connI->getPointer());
9151 MCAuto<DataArrayInt> c1(DataArrayInt::New()); c1->alloc((int)cNb1.size(),1); std::copy(cNb1.begin(),cNb1.end(),c1->getPointer());
9152 MCAuto<DataArrayInt> c2(DataArrayInt::New()); c2->alloc((int)cNb2.size(),1); std::copy(cNb2.begin(),cNb2.end(),c2->getPointer());
9153 ret->setConnectivity(conn,connI,true);
9154 ret->setCoords(coo);
9155 cellNb1=c1.retn(); cellNb2=c2.retn();
9161 bool IsColinearOfACellOf(const std::vector< std::vector<int> >& intersectEdge1, const std::vector<int>& candidates, int start, int stop, int& retVal)
9163 if(candidates.empty())
9165 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
9167 const std::vector<int>& pool(intersectEdge1[*it]);
9168 int tmp[2]; tmp[0]=start; tmp[1]=stop;
9169 if(std::search(pool.begin(),pool.end(),tmp,tmp+2)!=pool.end())
9174 tmp[0]=stop; tmp[1]=start;
9175 if(std::search(pool.begin(),pool.end(),tmp,tmp+2)!=pool.end())
9184 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,
9185 MCAuto<DataArrayInt>& idsInRetColinear, MCAuto<DataArrayInt>& idsInMesh1DForIdsInRetColinear)
9187 idsInRetColinear=DataArrayInt::New(); idsInRetColinear->alloc(0,1);
9188 idsInMesh1DForIdsInRetColinear=DataArrayInt::New(); idsInMesh1DForIdsInRetColinear->alloc(0,1);
9189 int nCells(mesh1D->getNumberOfCells());
9190 if(nCells!=(int)intersectEdge2.size())
9191 throw INTERP_KERNEL::Exception("BuildMesh1DCutFrom : internal error # 1 !");
9192 const DataArrayDouble *coo2(mesh1D->getCoords());
9193 const int *c(mesh1D->getNodalConnectivity()->begin()),*ci(mesh1D->getNodalConnectivityIndex()->begin());
9194 const double *coo2Ptr(coo2->begin());
9195 int offset1(coords1->getNumberOfTuples());
9196 int offset2(offset1+coo2->getNumberOfTuples());
9197 int offset3(offset2+addCoo.size()/2);
9198 std::vector<double> addCooQuad;
9199 MCAuto<DataArrayInt> cOut(DataArrayInt::New()),ciOut(DataArrayInt::New()); cOut->alloc(0,1); ciOut->alloc(1,1); ciOut->setIJ(0,0,0);
9200 int tmp[4],cicnt(0),kk(0);
9201 for(int i=0;i<nCells;i++)
9203 std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
9204 INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coo2Ptr,m));
9205 const std::vector<int>& subEdges(intersectEdge2[i]);
9206 int nbSubEdge(subEdges.size()/2);
9207 for(int j=0;j<nbSubEdge;j++,kk++)
9209 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));
9210 MCAuto<INTERP_KERNEL::Edge> e2(e->buildEdgeLyingOnMe(n1,n2));
9211 INTERP_KERNEL::Edge *e2Ptr(e2);
9212 std::map<int,int>::const_iterator itm;
9213 if(dynamic_cast<INTERP_KERNEL::EdgeArcCircle *>(e2Ptr))
9215 tmp[0]=INTERP_KERNEL::NORM_SEG3;
9216 itm=mergedNodes.find(subEdges[2*j]);
9217 tmp[1]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j];
9218 itm=mergedNodes.find(subEdges[2*j+1]);
9219 tmp[2]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j+1];
9220 tmp[3]=offset3+(int)addCooQuad.size()/2;
9222 e2->getBarycenter(tmp2); addCooQuad.insert(addCooQuad.end(),tmp2,tmp2+2);
9224 cOut->insertAtTheEnd(tmp,tmp+4);
9225 ciOut->pushBackSilent(cicnt);
9229 tmp[0]=INTERP_KERNEL::NORM_SEG2;
9230 itm=mergedNodes.find(subEdges[2*j]);
9231 tmp[1]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j];
9232 itm=mergedNodes.find(subEdges[2*j+1]);
9233 tmp[2]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j+1];
9235 cOut->insertAtTheEnd(tmp,tmp+3);
9236 ciOut->pushBackSilent(cicnt);
9239 if(IsColinearOfACellOf(intersectEdge1,colinear2[i],tmp[1],tmp[2],tmp00))
9241 idsInRetColinear->pushBackSilent(kk);
9242 idsInMesh1DForIdsInRetColinear->pushBackSilent(tmp00);
9247 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(mesh1D->getName(),1));
9248 ret->setConnectivity(cOut,ciOut,true);
9249 MCAuto<DataArrayDouble> arr3(DataArrayDouble::New());
9250 arr3->useArray(&addCoo[0],false,C_DEALLOC,(int)addCoo.size()/2,2);
9251 MCAuto<DataArrayDouble> arr4(DataArrayDouble::New()); arr4->useArray(&addCooQuad[0],false,C_DEALLOC,(int)addCooQuad.size()/2,2);
9252 std::vector<const DataArrayDouble *> coordss(4);
9253 coordss[0]=coords1; coordss[1]=mesh1D->getCoords(); coordss[2]=arr3; coordss[3]=arr4;
9254 MCAuto<DataArrayDouble> arr(DataArrayDouble::Aggregate(coordss));
9255 ret->setCoords(arr);
9259 MEDCouplingUMesh *BuildRefined2DCellLinear(const DataArrayDouble *coords, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9261 std::vector<int> allEdges;
9262 for(const int *it2(descBg);it2!=descEnd;it2++)
9264 const std::vector<int>& edge1(intersectEdge1[std::abs(*it2)-1]);
9266 allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9268 allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9270 std::size_t nb(allEdges.size());
9272 throw INTERP_KERNEL::Exception("BuildRefined2DCellLinear : internal error 1 !");
9273 std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9274 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
9275 ret->setCoords(coords);
9276 ret->allocateCells(1);
9277 std::vector<int> connOut(nbOfEdgesOf2DCellSplit);
9278 for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9279 connOut[kk]=allEdges[2*kk];
9280 ret->insertNextCell(INTERP_KERNEL::NORM_POLYGON,connOut.size(),&connOut[0]);
9284 MEDCouplingUMesh *BuildRefined2DCellQuadratic(const DataArrayDouble *coords, const MEDCouplingUMesh *mesh2D, int cellIdInMesh2D, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9286 const int *c(mesh2D->getNodalConnectivity()->begin()),*ci(mesh2D->getNodalConnectivityIndex()->begin());
9287 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[cellIdInMesh2D]]));
9289 unsigned sz(cm.getNumberOfSons2(c+ci[cellIdInMesh2D]+1,ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]-1));
9290 if(sz!=std::distance(descBg,descEnd))
9291 throw INTERP_KERNEL::Exception("BuildRefined2DCellQuadratic : internal error 1 !");
9292 INTERP_KERNEL::AutoPtr<int> tmpPtr(new int[ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]]);
9293 std::vector<int> allEdges,centers;
9294 const double *coordsPtr(coords->begin());
9295 MCAuto<DataArrayDouble> addCoo(DataArrayDouble::New()); addCoo->alloc(0,1);
9296 int offset(coords->getNumberOfTuples());
9297 for(const int *it2(descBg);it2!=descEnd;it2++,ii++)
9299 INTERP_KERNEL::NormalizedCellType typeOfSon;
9300 cm.fillSonCellNodalConnectivity2(ii,c+ci[cellIdInMesh2D]+1,ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]-1,tmpPtr,typeOfSon);
9301 const std::vector<int>& edge1(intersectEdge1[std::abs(*it2)-1]);
9303 allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9305 allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9307 centers.push_back(tmpPtr[2]);//special case where no subsplit of edge -> reuse the original center.
9309 {//the current edge has been subsplit -> create corresponding centers.
9310 std::size_t nbOfCentersToAppend(edge1.size()/2);
9311 std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9312 MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpPtr,coordsPtr,m));
9313 std::vector<int>::const_iterator it3(allEdges.end()-edge1.size());
9314 for(std::size_t k=0;k<nbOfCentersToAppend;k++)
9317 const double *aa(coordsPtr+2*(*it3++));
9318 const double *bb(coordsPtr+2*(*it3++));
9319 ee->getMiddleOfPoints(aa,bb,tmpp);
9320 addCoo->insertAtTheEnd(tmpp,tmpp+2);
9321 centers.push_back(offset+k);
9325 std::size_t nb(allEdges.size());
9327 throw INTERP_KERNEL::Exception("BuildRefined2DCellQuadratic : internal error 2 !");
9328 std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9329 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
9331 ret->setCoords(coords);
9334 addCoo->rearrange(2);
9335 addCoo=DataArrayDouble::Aggregate(coords,addCoo);
9336 ret->setCoords(addCoo);
9338 ret->allocateCells(1);
9339 std::vector<int> connOut(nbOfEdgesOf2DCellSplit);
9340 for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9341 connOut[kk]=allEdges[2*kk];
9342 connOut.insert(connOut.end(),centers.begin(),centers.end());
9343 ret->insertNextCell(INTERP_KERNEL::NORM_QPOLYG,connOut.size(),&connOut[0]);
9348 * This method creates a refinement of a cell in \a mesh2D. Those cell is defined by descending connectivity and the sorted subdivided nodal connectivity
9351 * \param [in] mesh2D - The origin 2D mesh. \b Warning \b coords are not those of \a mesh2D. But mesh2D->getCoords()==coords[:mesh2D->getNumberOfNodes()]
9353 MEDCouplingUMesh *BuildRefined2DCell(const DataArrayDouble *coords, const MEDCouplingUMesh *mesh2D, int cellIdInMesh2D, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9355 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(mesh2D->getTypeOfCell(cellIdInMesh2D)));
9356 if(!cm.isQuadratic())
9357 return BuildRefined2DCellLinear(coords,descBg,descEnd,intersectEdge1);
9359 return BuildRefined2DCellQuadratic(coords,mesh2D,cellIdInMesh2D,descBg,descEnd,intersectEdge1);
9362 void AddCellInMesh2D(MEDCouplingUMesh *mesh2D, const std::vector<int>& conn, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edges)
9365 for(std::vector< MCAuto<INTERP_KERNEL::Edge> >::const_iterator it=edges.begin();it!=edges.end();it++)
9367 const INTERP_KERNEL::Edge *ee(*it);
9368 if(dynamic_cast<const INTERP_KERNEL::EdgeArcCircle *>(ee))
9372 mesh2D->insertNextCell(INTERP_KERNEL::NORM_POLYGON,conn.size(),&conn[0]);
9375 const double *coo(mesh2D->getCoords()->begin());
9376 std::size_t sz(conn.size());
9377 std::vector<double> addCoo;
9378 std::vector<int> conn2(conn);
9379 int offset(mesh2D->getNumberOfNodes());
9380 for(std::size_t i=0;i<sz;i++)
9383 edges[(i+1)%sz]->getMiddleOfPoints(coo+2*conn[i],coo+2*conn[(i+1)%sz],tmp);// tony a chier i+1 -> i
9384 addCoo.insert(addCoo.end(),tmp,tmp+2);
9385 conn2.push_back(offset+(int)i);
9387 mesh2D->getCoords()->rearrange(1);
9388 mesh2D->getCoords()->pushBackValsSilent(&addCoo[0],&addCoo[0]+addCoo.size());
9389 mesh2D->getCoords()->rearrange(2);
9390 mesh2D->insertNextCell(INTERP_KERNEL::NORM_QPOLYG,conn2.size(),&conn2[0]);
9395 * \b WARNING edges in out1 coming from \a splitMesh1D are \b NOT oriented because only used for equation of curve.
9397 * This method cuts in 2 parts the input 2D cell given using boundaries description (\a edge1Bis and \a edge1BisPtr) using
9398 * a set of edges defined in \a splitMesh1D.
9400 void BuildMesh2DCutInternal2(const MEDCouplingUMesh *splitMesh1D, const std::vector<int>& edge1Bis, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edge1BisPtr,
9401 std::vector< std::vector<int> >& out0, std::vector< std::vector< MCAuto<INTERP_KERNEL::Edge> > >& out1)
9403 std::size_t nb(edge1Bis.size()/2);
9404 std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9405 int iEnd(splitMesh1D->getNumberOfCells());
9407 throw INTERP_KERNEL::Exception("BuildMesh2DCutInternal2 : internal error ! input 1D mesh must have at least one cell !");
9409 const int *cSplitPtr(splitMesh1D->getNodalConnectivity()->begin()),*ciSplitPtr(splitMesh1D->getNodalConnectivityIndex()->begin());
9410 for(ii=0;ii<nb && edge1Bis[2*ii]!=cSplitPtr[ciSplitPtr[0]+1];ii++);
9411 for(jj=ii;jj<nb && edge1Bis[2*jj+1]!=cSplitPtr[ciSplitPtr[iEnd-1]+2];jj++);
9414 {//the edges splitMesh1D[iStart:iEnd] does not fully cut the current 2D cell -> single output cell
9415 out0.resize(1); out1.resize(1);
9416 std::vector<int>& connOut(out0[0]);
9417 connOut.resize(nbOfEdgesOf2DCellSplit);
9418 std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr(out1[0]);
9419 edgesPtr.resize(nbOfEdgesOf2DCellSplit);
9420 for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9422 connOut[kk]=edge1Bis[2*kk];
9423 edgesPtr[kk]=edge1BisPtr[2*kk];
9428 // [i,iEnd[ contains the
9429 out0.resize(2); out1.resize(2);
9430 std::vector<int>& connOutLeft(out0[0]);
9431 std::vector<int>& connOutRight(out0[1]);//connOutLeft should end with edge1Bis[2*ii] and connOutRight should end with edge1Bis[2*jj+1]
9432 std::vector< MCAuto<INTERP_KERNEL::Edge> >& eleft(out1[0]);
9433 std::vector< MCAuto<INTERP_KERNEL::Edge> >& eright(out1[1]);
9434 for(std::size_t k=ii;k<jj+1;k++)
9435 { connOutLeft.push_back(edge1Bis[2*k+1]); eleft.push_back(edge1BisPtr[2*k+1]); }
9436 std::vector< MCAuto<INTERP_KERNEL::Edge> > ees(iEnd);
9437 for(int ik=0;ik<iEnd;ik++)
9439 std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9440 MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)cSplitPtr[ciSplitPtr[ik]],cSplitPtr+ciSplitPtr[ik]+1,splitMesh1D->getCoords()->begin(),m));
9443 for(int ik=iEnd-1;ik>=0;ik--)
9444 connOutLeft.push_back(cSplitPtr[ciSplitPtr[ik]+1]);
9445 for(std::size_t k=jj+1;k<nbOfEdgesOf2DCellSplit+ii;k++)
9446 { connOutRight.push_back(edge1Bis[2*k+1]); eright.push_back(edge1BisPtr[2*k+1]); }
9447 eleft.insert(eleft.end(),ees.rbegin(),ees.rend());
9448 for(int ik=0;ik<iEnd;ik++)
9449 connOutRight.push_back(cSplitPtr[ciSplitPtr[ik]+2]);
9450 eright.insert(eright.end(),ees.begin(),ees.end());
9462 CellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr);
9464 std::vector<int> _edges;
9465 std::vector< MCAuto<INTERP_KERNEL::Edge> > _edges_ptr;
9468 CellInfo::CellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr)
9470 std::size_t nbe(edges.size());
9471 std::vector<int> edges2(2*nbe); std::vector< MCAuto<INTERP_KERNEL::Edge> > edgesPtr2(2*nbe);
9472 for(std::size_t i=0;i<nbe;i++)
9474 edges2[2*i]=edges[i]; edges2[2*i+1]=edges[(i+1)%nbe];
9475 edgesPtr2[2*i]=edgesPtr[(i+1)%nbe]; edgesPtr2[2*i+1]=edgesPtr[(i+1)%nbe];//tony a chier
9477 _edges.resize(4*nbe); _edges_ptr.resize(4*nbe);
9478 std::copy(edges2.begin(),edges2.end(),_edges.begin()); std::copy(edges2.begin(),edges2.end(),_edges.begin()+2*nbe);
9479 std::copy(edgesPtr2.begin(),edgesPtr2.end(),_edges_ptr.begin()); std::copy(edgesPtr2.begin(),edgesPtr2.end(),_edges_ptr.begin()+2*nbe);
9485 EdgeInfo(int istart, int iend, const MCAuto<MEDCouplingUMesh>& mesh):_istart(istart),_iend(iend),_mesh(mesh),_left(-7),_right(-7) { }
9486 EdgeInfo(int istart, int iend, int pos, const MCAuto<INTERP_KERNEL::Edge>& edge):_istart(istart),_iend(iend),_edge(edge),_left(pos),_right(pos+1) { }
9487 bool isInMyRange(int pos) const { return pos>=_istart && pos<_iend; }
9488 void somethingHappendAt(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight);
9489 void feedEdgeInfoAt(double eps, const MEDCouplingUMesh *mesh2D, int offset, int neighbors[2]) const;
9493 MCAuto<MEDCouplingUMesh> _mesh;
9494 MCAuto<INTERP_KERNEL::Edge> _edge;
9499 void EdgeInfo::somethingHappendAt(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight)
9501 const MEDCouplingUMesh *mesh(_mesh);
9507 { _left++; _right++; return ; }
9510 bool isLeft(std::find(newLeft.begin(),newLeft.end(),_edge)!=newLeft.end()),isRight(std::find(newRight.begin(),newRight.end(),_edge)!=newRight.end());
9511 if((isLeft && isRight) || (!isLeft && !isRight))
9512 throw INTERP_KERNEL::Exception("EdgeInfo::somethingHappendAt : internal error # 1 !");
9523 bool isLeft(std::find(newLeft.begin(),newLeft.end(),_edge)!=newLeft.end()),isRight(std::find(newRight.begin(),newRight.end(),_edge)!=newRight.end());
9524 if((isLeft && isRight) || (!isLeft && !isRight))
9525 throw INTERP_KERNEL::Exception("EdgeInfo::somethingHappendAt : internal error # 2 !");
9540 void EdgeInfo::feedEdgeInfoAt(double eps, const MEDCouplingUMesh *mesh2D, int offset, int neighbors[2]) const
9542 const MEDCouplingUMesh *mesh(_mesh);
9545 neighbors[0]=offset+_left; neighbors[1]=offset+_right;
9548 {// not fully splitting cell case
9549 if(mesh2D->getNumberOfCells()==1)
9550 {//little optimization. 1 cell no need to find in which cell mesh is !
9551 neighbors[0]=offset; neighbors[1]=offset;
9556 MCAuto<DataArrayDouble> barys(mesh->computeCellCenterOfMass());
9557 int cellId(mesh2D->getCellContainingPoint(barys->begin(),eps));
9559 throw INTERP_KERNEL::Exception("EdgeInfo::feedEdgeInfoAt : internal error !");
9560 neighbors[0]=offset+cellId; neighbors[1]=offset+cellId;
9565 class VectorOfCellInfo
9568 VectorOfCellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr);
9569 std::size_t size() const { return _pool.size(); }
9570 int getPositionOf(double eps, const MEDCouplingUMesh *mesh) const;
9571 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);
9572 const std::vector<int>& getConnOf(int pos) const { return get(pos)._edges; }
9573 const std::vector< MCAuto<INTERP_KERNEL::Edge> >& getEdgePtrOf(int pos) const { return get(pos)._edges_ptr; }
9574 MCAuto<MEDCouplingUMesh> getZeMesh() const { return _ze_mesh; }
9575 void feedEdgeInfoAt(double eps, int pos, int offset, int neighbors[2]) const;
9577 int getZePosOfEdgeGivenItsGlobalId(int pos) const;
9578 void updateEdgeInfo(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight);
9579 const CellInfo& get(int pos) const;
9580 CellInfo& get(int pos);
9582 std::vector<CellInfo> _pool;
9583 MCAuto<MEDCouplingUMesh> _ze_mesh;
9584 std::vector<EdgeInfo> _edge_info;
9587 VectorOfCellInfo::VectorOfCellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr):_pool(1)
9589 _pool[0]._edges=edges;
9590 _pool[0]._edges_ptr=edgesPtr;
9593 int VectorOfCellInfo::getPositionOf(double eps, const MEDCouplingUMesh *mesh) const
9596 throw INTERP_KERNEL::Exception("VectorOfCellSplitter::getPositionOf : empty !");
9599 const MEDCouplingUMesh *zeMesh(_ze_mesh);
9601 throw INTERP_KERNEL::Exception("VectorOfCellSplitter::getPositionOf : null aggregated mesh !");
9602 MCAuto<DataArrayDouble> barys(mesh->computeCellCenterOfMass());
9603 return zeMesh->getCellContainingPoint(barys->begin(),eps);
9606 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)
9608 get(pos);//to check pos
9609 bool isFast(pos==0 && _pool.size()==1);
9610 std::size_t sz(edges.size());
9611 // dealing with edges
9613 _edge_info.push_back(EdgeInfo(istart,iend,mesh1DInCase));
9615 _edge_info.push_back(EdgeInfo(istart,iend,pos,edgePtrs[0].back()));
9617 std::vector<CellInfo> pool(_pool.size()-1+sz);
9618 for(int i=0;i<pos;i++)
9620 for(std::size_t j=0;j<sz;j++)
9621 pool[pos+j]=CellInfo(edges[j],edgePtrs[j]);
9622 for(int i=pos+1;i<(int)_pool.size();i++)
9623 pool[i+sz-1]=_pool[i];
9627 updateEdgeInfo(pos,edgePtrs[0],edgePtrs[1]);
9635 std::vector< MCAuto<MEDCouplingUMesh> > ms;
9638 MCAuto<MEDCouplingUMesh> elt(static_cast<MEDCouplingUMesh *>(_ze_mesh->buildPartOfMySelfSlice(0,pos,true)));
9642 if(pos<_ze_mesh->getNumberOfCells()-1)
9644 MCAuto<MEDCouplingUMesh> elt(static_cast<MEDCouplingUMesh *>(_ze_mesh->buildPartOfMySelfSlice(pos+1,_ze_mesh->getNumberOfCells(),true)));
9647 std::vector< const MEDCouplingUMesh *> ms2(ms.size());
9648 for(std::size_t j=0;j<ms2.size();j++)
9650 _ze_mesh=MEDCouplingUMesh::MergeUMeshesOnSameCoords(ms2);
9653 void VectorOfCellInfo::feedEdgeInfoAt(double eps, int pos, int offset, int neighbors[2]) const
9655 _edge_info[getZePosOfEdgeGivenItsGlobalId(pos)].feedEdgeInfoAt(eps,_ze_mesh,offset,neighbors);
9658 int VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId(int pos) const
9661 throw INTERP_KERNEL::Exception("VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId : invalid id ! Must be >=0 !");
9663 for(std::vector<EdgeInfo>::const_iterator it=_edge_info.begin();it!=_edge_info.end();it++,ret++)
9665 if((*it).isInMyRange(pos))
9668 throw INTERP_KERNEL::Exception("VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId : invalid id !");
9671 void VectorOfCellInfo::updateEdgeInfo(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight)
9673 get(pos);//to check;
9674 if(_edge_info.empty())
9676 std::size_t sz(_edge_info.size()-1);
9677 for(std::size_t i=0;i<sz;i++)
9678 _edge_info[i].somethingHappendAt(pos,newLeft,newRight);
9681 const CellInfo& VectorOfCellInfo::get(int pos) const
9683 if(pos<0 || pos>=(int)_pool.size())
9684 throw INTERP_KERNEL::Exception("VectorOfCellSplitter::get const : invalid pos !");
9688 CellInfo& VectorOfCellInfo::get(int pos)
9690 if(pos<0 || pos>=(int)_pool.size())
9691 throw INTERP_KERNEL::Exception("VectorOfCellSplitter::get : invalid pos !");
9697 * - a \b closed set of edges ( \a allEdges and \a allEdgesPtr ) that defines the split descending 2D cell.
9698 * - \a splitMesh1D a split 2D curve mesh contained into 2D cell defined above.
9700 * This method returns the 2D mesh and feeds \a idsLeftRight using offset.
9702 * Algorithm : \a splitMesh1D is cut into contiguous parts. Each contiguous parts will build incrementally the output 2D cells.
9704 * \param [in] allEdges a list of pairs (beginNode, endNode). Linked with \a allEdgesPtr to get the equation of edge.
9706 MEDCouplingUMesh *BuildMesh2DCutInternal(double eps, const MEDCouplingUMesh *splitMesh1D, const std::vector<int>& allEdges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& allEdgesPtr, int offset,
9707 MCAuto<DataArrayInt>& idsLeftRight)
9709 int nbCellsInSplitMesh1D(splitMesh1D->getNumberOfCells());
9710 if(nbCellsInSplitMesh1D==0)
9711 throw INTERP_KERNEL::Exception("BuildMesh2DCutInternal : internal error ! input 1D mesh must have at least one cell !");
9712 const int *cSplitPtr(splitMesh1D->getNodalConnectivity()->begin()),*ciSplitPtr(splitMesh1D->getNodalConnectivityIndex()->begin());
9713 std::size_t nb(allEdges.size()),jj;
9715 throw INTERP_KERNEL::Exception("BuildMesh2DCutFrom : internal error 2 !");
9716 std::vector<int> edge1Bis(nb*2);
9717 std::vector< MCAuto<INTERP_KERNEL::Edge> > edge1BisPtr(nb*2);
9718 std::copy(allEdges.begin(),allEdges.end(),edge1Bis.begin());
9719 std::copy(allEdges.begin(),allEdges.end(),edge1Bis.begin()+nb);
9720 std::copy(allEdgesPtr.begin(),allEdgesPtr.end(),edge1BisPtr.begin());
9721 std::copy(allEdgesPtr.begin(),allEdgesPtr.end(),edge1BisPtr.begin()+nb);
9723 idsLeftRight=DataArrayInt::New(); idsLeftRight->alloc(nbCellsInSplitMesh1D*2); idsLeftRight->fillWithValue(-2); idsLeftRight->rearrange(2);
9724 int *idsLeftRightPtr(idsLeftRight->getPointer());
9725 VectorOfCellInfo pool(edge1Bis,edge1BisPtr);
9726 for(int iStart=0;iStart<nbCellsInSplitMesh1D;)
9727 {// split [0:nbCellsInSplitMesh1D) in contiguous parts [iStart:iEnd)
9729 for(;iEnd<nbCellsInSplitMesh1D;)
9731 for(jj=0;jj<nb && edge1Bis[2*jj+1]!=cSplitPtr[ciSplitPtr[iEnd]+2];jj++);
9737 if(iEnd<nbCellsInSplitMesh1D)
9740 MCAuto<MEDCouplingUMesh> partOfSplitMesh1D(static_cast<MEDCouplingUMesh *>(splitMesh1D->buildPartOfMySelfSlice(iStart,iEnd,1,true)));
9741 int pos(pool.getPositionOf(eps,partOfSplitMesh1D));
9743 MCAuto<MEDCouplingUMesh>retTmp(MEDCouplingUMesh::New("",2));
9744 retTmp->setCoords(splitMesh1D->getCoords());
9745 retTmp->allocateCells();
9747 std::vector< std::vector<int> > out0;
9748 std::vector< std::vector< MCAuto<INTERP_KERNEL::Edge> > > out1;
9750 BuildMesh2DCutInternal2(partOfSplitMesh1D,pool.getConnOf(pos),pool.getEdgePtrOf(pos),out0,out1);
9751 for(std::size_t cnt=0;cnt<out0.size();cnt++)
9752 AddCellInMesh2D(retTmp,out0[cnt],out1[cnt]);
9753 pool.setMeshAt(pos,retTmp,iStart,iEnd,partOfSplitMesh1D,out0,out1);
9757 for(int mm=0;mm<nbCellsInSplitMesh1D;mm++)
9758 pool.feedEdgeInfoAt(eps,mm,offset,idsLeftRightPtr+2*mm);
9759 return pool.getZeMesh().retn();
9762 MEDCouplingUMesh *BuildMesh2DCutFrom(double eps, int cellIdInMesh2D, const MEDCouplingUMesh *mesh2DDesc, const MEDCouplingUMesh *splitMesh1D,
9763 const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1, int offset,
9764 MCAuto<DataArrayInt>& idsLeftRight)
9766 const int *cdescPtr(mesh2DDesc->getNodalConnectivity()->begin()),*cidescPtr(mesh2DDesc->getNodalConnectivityIndex()->begin());
9768 std::vector<int> allEdges;
9769 std::vector< MCAuto<INTERP_KERNEL::Edge> > allEdgesPtr; // for each sub edge in splitMesh2D the uncut Edge object of the original mesh2D
9770 for(const int *it(descBg);it!=descEnd;it++) // for all edges in the descending connectivity of the 2D mesh in relative Fortran mode
9772 int edgeId(std::abs(*it)-1);
9773 std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9774 MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)cdescPtr[cidescPtr[edgeId]],cdescPtr+cidescPtr[edgeId]+1,mesh2DDesc->getCoords()->begin(),m));
9775 const std::vector<int>& edge1(intersectEdge1[edgeId]);
9777 allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9779 allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9780 std::size_t sz(edge1.size());
9781 for(std::size_t cnt=0;cnt<sz;cnt++)
9782 allEdgesPtr.push_back(ee);
9785 return BuildMesh2DCutInternal(eps,splitMesh1D,allEdges,allEdgesPtr,offset,idsLeftRight);
9788 bool AreEdgeEqual(const double *coo2D, const INTERP_KERNEL::CellModel& typ1, const int *conn1, const INTERP_KERNEL::CellModel& typ2, const int *conn2, double eps)
9790 if(!typ1.isQuadratic() && !typ2.isQuadratic())
9791 {//easy case comparison not
9792 return conn1[0]==conn2[0] && conn1[1]==conn2[1];
9794 else if(typ1.isQuadratic() && typ2.isQuadratic())
9796 bool status0(conn1[0]==conn2[0] && conn1[1]==conn2[1]);
9799 if(conn1[2]==conn2[2])
9801 const double *a(coo2D+2*conn1[2]),*b(coo2D+2*conn2[2]);
9802 double dist(sqrt((a[0]-b[0])*(a[0]-b[0])+(a[1]-b[1])*(a[1]-b[1])));
9806 {//only one is quadratic
9807 bool status0(conn1[0]==conn2[0] && conn1[1]==conn2[1]);
9810 const double *a(0),*bb(0),*be(0);
9811 if(typ1.isQuadratic())
9813 a=coo2D+2*conn1[2]; bb=coo2D+2*conn2[0]; be=coo2D+2*conn2[1];
9817 a=coo2D+2*conn2[2]; bb=coo2D+2*conn1[0]; be=coo2D+2*conn1[1];
9819 double b[2]; b[0]=(be[0]+bb[0])/2.; b[1]=(be[1]+bb[1])/2.;
9820 double dist(sqrt((a[0]-b[0])*(a[0]-b[0])+(a[1]-b[1])*(a[1]-b[1])));
9826 * This method returns among the cellIds [ \a candidatesIn2DBg , \a candidatesIn2DEnd ) in \a mesh2DSplit those exactly sharing \a cellIdInMesh1DSplitRelative in \a mesh1DSplit.
9827 * \a mesh2DSplit and \a mesh1DSplit are expected to share the coordinates array.
9829 * \param [in] cellIdInMesh1DSplitRelative is in Fortran mode using sign to specify direction.
9831 int FindRightCandidateAmong(const MEDCouplingUMesh *mesh2DSplit, const int *candidatesIn2DBg, const int *candidatesIn2DEnd, const MEDCouplingUMesh *mesh1DSplit, int cellIdInMesh1DSplitRelative, double eps)
9833 if(candidatesIn2DEnd==candidatesIn2DBg)
9834 throw INTERP_KERNEL::Exception("FindRightCandidateAmong : internal error 1 !");
9835 const double *coo(mesh2DSplit->getCoords()->begin());
9836 if(std::distance(candidatesIn2DBg,candidatesIn2DEnd)==1)
9837 return *candidatesIn2DBg;
9838 int edgeId(std::abs(cellIdInMesh1DSplitRelative)-1);
9839 MCAuto<MEDCouplingUMesh> cur1D(static_cast<MEDCouplingUMesh *>(mesh1DSplit->buildPartOfMySelf(&edgeId,&edgeId+1,true)));
9840 if(cellIdInMesh1DSplitRelative<0)
9841 cur1D->changeOrientationOfCells();
9842 const int *c1D(cur1D->getNodalConnectivity()->begin());
9843 const INTERP_KERNEL::CellModel& ref1DType(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c1D[0]));
9844 for(const int *it=candidatesIn2DBg;it!=candidatesIn2DEnd;it++)
9846 MCAuto<MEDCouplingUMesh> cur2D(static_cast<MEDCouplingUMesh *>(mesh2DSplit->buildPartOfMySelf(it,it+1,true)));
9847 const int *c(cur2D->getNodalConnectivity()->begin()),*ci(cur2D->getNodalConnectivityIndex()->begin());
9848 const INTERP_KERNEL::CellModel &cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[0]]));
9849 unsigned sz(cm.getNumberOfSons2(c+ci[0]+1,ci[1]-ci[0]-1));
9850 INTERP_KERNEL::AutoPtr<int> tmpPtr(new int[ci[1]-ci[0]]);
9851 for(unsigned it2=0;it2<sz;it2++)
9853 INTERP_KERNEL::NormalizedCellType typeOfSon;
9854 cm.fillSonCellNodalConnectivity2(it2,c+ci[0]+1,ci[1]-ci[0]-1,tmpPtr,typeOfSon);
9855 const INTERP_KERNEL::CellModel &curCM(INTERP_KERNEL::CellModel::GetCellModel(typeOfSon));
9856 if(AreEdgeEqual(coo,ref1DType,c1D+1,curCM,tmpPtr,eps))
9860 throw INTERP_KERNEL::Exception("FindRightCandidateAmong : internal error 2 ! Unable to find the edge among split cell !");
9866 * Partitions the first given 2D mesh using the second given 1D mesh as a tool.
9867 * 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
9868 * and finaly, in case of quadratic polygon the centers of edges new nodes.
9869 * The meshes should be in 2D space. In addition, returns two arrays mapping cells of the resulting mesh to cells of the input.
9871 * \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
9872 * 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)
9873 * \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
9874 * you can invoke orderConsecutiveCells1D on \a mesh1D.
9875 * \param [in] eps - precision used to perform intersections and localization operations.
9876 * \param [out] splitMesh2D - the result of the split of \a mesh2D mesh.
9877 * \param [out] splitMesh1D - the result of the split of \a mesh1D mesh.
9878 * \param [out] cellIdInMesh2D - the array that gives for each cell id \a i in \a splitMesh2D the id in \a mesh2D it comes from.
9879 * 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.
9880 * \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
9881 * and the cell in \a splitMesh2D on the right for the 2nt component. -1 means no cell.
9882 * 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.
9884 * \sa Intersect2DMeshes, orderConsecutiveCells1D, conformize2D, mergeNodes
9886 void MEDCouplingUMesh::Intersect2DMeshWith1DLine(const MEDCouplingUMesh *mesh2D, const MEDCouplingUMesh *mesh1D, double eps, MEDCouplingUMesh *&splitMesh2D, MEDCouplingUMesh *&splitMesh1D, DataArrayInt *&cellIdInMesh2D, DataArrayInt *&cellIdInMesh1D)
9888 if(!mesh2D || !mesh1D)
9889 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshWith1DLine : input meshes must be not NULL !");
9890 mesh2D->checkFullyDefined();
9891 mesh1D->checkFullyDefined();
9892 const std::vector<std::string>& compNames(mesh2D->getCoords()->getInfoOnComponents());
9893 if(mesh2D->getMeshDimension()!=2 || mesh2D->getSpaceDimension()!=2 || mesh1D->getMeshDimension()!=1 || mesh1D->getSpaceDimension()!=2)
9894 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshWith1DLine works with mesh2D with spacedim=meshdim=2 and mesh1D with meshdim=1 spaceDim=2 !");
9895 // Step 1: compute all edge intersections (new nodes)
9896 std::vector< std::vector<int> > intersectEdge1, colinear2, subDiv2;
9897 std::vector<double> addCoo,addCoordsQuadratic; // coordinates of newly created nodes
9898 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
9899 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
9901 // Build desc connectivity
9902 DataArrayInt *desc1(DataArrayInt::New()),*descIndx1(DataArrayInt::New()),*revDesc1(DataArrayInt::New()),*revDescIndx1(DataArrayInt::New());
9903 MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(revDesc1),dd4(revDescIndx1);
9904 MCAuto<MEDCouplingUMesh> m1Desc(mesh2D->buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1));
9905 std::map<int,int> mergedNodes;
9906 Intersect1DMeshes(m1Desc,mesh1D,eps,intersectEdge1,colinear2,subDiv2,addCoo,mergedNodes);
9907 // use mergeNodes to fix intersectEdge1
9908 for(std::vector< std::vector<int> >::iterator it0=intersectEdge1.begin();it0!=intersectEdge1.end();it0++)
9910 std::size_t n((*it0).size()/2);
9911 int eltStart((*it0)[0]),eltEnd((*it0)[2*n-1]);
9912 std::map<int,int>::const_iterator it1;
9913 it1=mergedNodes.find(eltStart);
9914 if(it1!=mergedNodes.end())
9915 (*it0)[0]=(*it1).second;
9916 it1=mergedNodes.find(eltEnd);
9917 if(it1!=mergedNodes.end())
9918 (*it0)[2*n-1]=(*it1).second;
9921 MCAuto<DataArrayDouble> addCooDa(DataArrayDouble::New());
9922 addCooDa->useArray(&addCoo[0],false,C_DEALLOC,(int)addCoo.size()/2,2);
9923 // Step 2: re-order newly created nodes according to the ordering found in m2
9924 std::vector< std::vector<int> > intersectEdge2;
9925 BuildIntersectEdges(m1Desc,mesh1D,addCoo,subDiv2,intersectEdge2);
9927 // Step 3: compute splitMesh1D
9928 MCAuto<DataArrayInt> idsInRet1Colinear,idsInDescMesh2DForIdsInRetColinear;
9929 MCAuto<DataArrayInt> ret2(DataArrayInt::New()); ret2->alloc(0,1);
9930 MCAuto<MEDCouplingUMesh> ret1(BuildMesh1DCutFrom(mesh1D,intersectEdge2,mesh2D->getCoords(),addCoo,mergedNodes,colinear2,intersectEdge1,
9931 idsInRet1Colinear,idsInDescMesh2DForIdsInRetColinear));
9932 MCAuto<DataArrayInt> ret3(DataArrayInt::New()); ret3->alloc(ret1->getNumberOfCells()*2,1); ret3->fillWithValue(std::numeric_limits<int>::max()); ret3->rearrange(2);
9933 MCAuto<DataArrayInt> idsInRet1NotColinear(idsInRet1Colinear->buildComplement(ret1->getNumberOfCells()));
9934 // deal with cells in mesh2D that are not cut but only some of their edges are
9935 MCAuto<DataArrayInt> idsInDesc2DToBeRefined(idsInDescMesh2DForIdsInRetColinear->deepCopy());
9936 idsInDesc2DToBeRefined->abs(); idsInDesc2DToBeRefined->applyLin(1,-1);
9937 idsInDesc2DToBeRefined=idsInDesc2DToBeRefined->buildUnique();
9938 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
9939 if(!idsInDesc2DToBeRefined->empty())
9941 DataArrayInt *out0(0),*outi0(0);
9942 MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
9943 MCAuto<DataArrayInt> outi0s(outi0);
9945 out0s=out0s->buildUnique();
9949 MCAuto<MEDCouplingUMesh> ret1NonCol(static_cast<MEDCouplingUMesh *>(ret1->buildPartOfMySelf(idsInRet1NotColinear->begin(),idsInRet1NotColinear->end())));
9950 MCAuto<DataArrayDouble> baryRet1(ret1NonCol->computeCellCenterOfMass());
9951 MCAuto<DataArrayInt> elts,eltsIndex;
9952 mesh2D->getCellsContainingPoints(baryRet1->begin(),baryRet1->getNumberOfTuples(),eps,elts,eltsIndex);
9953 MCAuto<DataArrayInt> eltsIndex2(eltsIndex->deltaShiftIndex());
9954 MCAuto<DataArrayInt> eltsIndex3(eltsIndex2->findIdsEqual(1));
9955 if(eltsIndex2->count(0)+eltsIndex3->getNumberOfTuples()!=ret1NonCol->getNumberOfCells())
9956 throw INTERP_KERNEL::Exception("Intersect2DMeshWith1DLine : internal error 1 !");
9957 MCAuto<DataArrayInt> cellsToBeModified(elts->buildUnique());
9958 MCAuto<DataArrayInt> untouchedCells(cellsToBeModified->buildComplement(mesh2D->getNumberOfCells()));
9959 if((DataArrayInt *)out0s)
9960 untouchedCells=untouchedCells->buildSubstraction(out0s);//if some edges in ret1 are colinear to descending mesh of mesh2D remove cells from untouched one
9961 std::vector< MCAuto<MEDCouplingUMesh> > outMesh2DSplit;
9962 // OK all is ready to insert in ret2 mesh
9963 if(!untouchedCells->empty())
9964 {// the most easy part, cells in mesh2D not impacted at all
9965 outMesh2DSplit.push_back(static_cast<MEDCouplingUMesh *>(mesh2D->buildPartOfMySelf(untouchedCells->begin(),untouchedCells->end())));
9966 outMesh2DSplit.back()->setCoords(ret1->getCoords());
9967 ret2->pushBackValsSilent(untouchedCells->begin(),untouchedCells->end());
9969 if((DataArrayInt *)out0s)
9970 {// here dealing with cells in out0s but not in cellsToBeModified
9971 MCAuto<DataArrayInt> fewModifiedCells(out0s->buildSubstraction(cellsToBeModified));
9972 const int *rdptr(dd3->begin()),*rdiptr(dd4->begin()),*dptr(dd1->begin()),*diptr(dd2->begin());
9973 for(const int *it=fewModifiedCells->begin();it!=fewModifiedCells->end();it++)
9975 outMesh2DSplit.push_back(BuildRefined2DCell(ret1->getCoords(),mesh2D,*it,dptr+diptr[*it],dptr+diptr[*it+1],intersectEdge1));
9976 ret1->setCoords(outMesh2DSplit.back()->getCoords());
9978 int offset(ret2->getNumberOfTuples());
9979 ret2->pushBackValsSilent(fewModifiedCells->begin(),fewModifiedCells->end());
9980 MCAuto<DataArrayInt> partOfRet3(DataArrayInt::New()); partOfRet3->alloc(2*idsInRet1Colinear->getNumberOfTuples(),1);
9981 partOfRet3->fillWithValue(std::numeric_limits<int>::max()); partOfRet3->rearrange(2);
9982 int kk(0),*ret3ptr(partOfRet3->getPointer());
9983 for(const int *it=idsInDescMesh2DForIdsInRetColinear->begin();it!=idsInDescMesh2DForIdsInRetColinear->end();it++,kk++)
9985 int faceId(std::abs(*it)-1);
9986 for(const int *it2=rdptr+rdiptr[faceId];it2!=rdptr+rdiptr[faceId+1];it2++)
9988 int tmp(fewModifiedCells->findIdFirstEqual(*it2));
9991 if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],-(*it))!=dptr+diptr[*it2+1])
9992 ret3ptr[2*kk]=tmp+offset;
9993 if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],(*it))!=dptr+diptr[*it2+1])
9994 ret3ptr[2*kk+1]=tmp+offset;
9997 {//the current edge is shared by a 2D cell that will be split just after
9998 if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],-(*it))!=dptr+diptr[*it2+1])
9999 ret3ptr[2*kk]=-(*it2+1);
10000 if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],(*it))!=dptr+diptr[*it2+1])
10001 ret3ptr[2*kk+1]=-(*it2+1);
10005 m1Desc->setCoords(ret1->getCoords());
10006 ret1NonCol->setCoords(ret1->getCoords());
10007 ret3->setPartOfValues3(partOfRet3,idsInRet1Colinear->begin(),idsInRet1Colinear->end(),0,2,1,true);
10008 if(!outMesh2DSplit.empty())
10010 DataArrayDouble *da(outMesh2DSplit.back()->getCoords());
10011 for(std::vector< MCAuto<MEDCouplingUMesh> >::iterator itt=outMesh2DSplit.begin();itt!=outMesh2DSplit.end();itt++)
10012 (*itt)->setCoords(da);
10015 cellsToBeModified=cellsToBeModified->buildUniqueNotSorted();
10016 for(const int *it=cellsToBeModified->begin();it!=cellsToBeModified->end();it++)
10018 MCAuto<DataArrayInt> idsNonColPerCell(elts->findIdsEqual(*it));
10019 idsNonColPerCell->transformWithIndArr(eltsIndex3->begin(),eltsIndex3->end());
10020 MCAuto<DataArrayInt> idsNonColPerCell2(idsInRet1NotColinear->selectByTupleId(idsNonColPerCell->begin(),idsNonColPerCell->end()));
10021 MCAuto<MEDCouplingUMesh> partOfMesh1CuttingCur2DCell(static_cast<MEDCouplingUMesh *>(ret1NonCol->buildPartOfMySelf(idsNonColPerCell->begin(),idsNonColPerCell->end())));
10022 MCAuto<DataArrayInt> partOfRet3;
10023 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));
10024 ret3->setPartOfValues3(partOfRet3,idsNonColPerCell2->begin(),idsNonColPerCell2->end(),0,2,1,true);
10025 outMesh2DSplit.push_back(splitOfOneCell);
10026 for(int i=0;i<splitOfOneCell->getNumberOfCells();i++)
10027 ret2->pushBackSilent(*it);
10030 std::size_t nbOfMeshes(outMesh2DSplit.size());
10031 std::vector<const MEDCouplingUMesh *> tmp(nbOfMeshes);
10032 for(std::size_t i=0;i<nbOfMeshes;i++)
10033 tmp[i]=outMesh2DSplit[i];
10035 ret1->getCoords()->setInfoOnComponents(compNames);
10036 MCAuto<MEDCouplingUMesh> ret2D(MEDCouplingUMesh::MergeUMeshesOnSameCoords(tmp));
10037 // To finish - filter ret3 - std::numeric_limits<int>::max() -> -1 - negate values must be resolved.
10038 ret3->rearrange(1);
10039 MCAuto<DataArrayInt> edgesToDealWith(ret3->findIdsStricltyNegative());
10040 for(const int *it=edgesToDealWith->begin();it!=edgesToDealWith->end();it++)
10042 int old2DCellId(-ret3->getIJ(*it,0)-1);
10043 MCAuto<DataArrayInt> candidates(ret2->findIdsEqual(old2DCellId));
10044 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
10046 ret3->changeValue(std::numeric_limits<int>::max(),-1);
10047 ret3->rearrange(2);
10049 splitMesh1D=ret1.retn();
10050 splitMesh2D=ret2D.retn();
10051 cellIdInMesh2D=ret2.retn();
10052 cellIdInMesh1D=ret3.retn();
10056 * Private. Third step of the partitioning algorithm (Intersect2DMeshes): reconstruct full 2D cells from the
10057 * (newly created) nodes corresponding to the edge intersections.
10059 * @param[out] cr, crI connectivity of the resulting mesh
10060 * @param[out] cNb1, cNb2 correspondance arrays giving for the merged mesh the initial cells IDs in m1 / m2
10061 * TODO: describe input parameters
10063 void MEDCouplingUMesh::BuildIntersecting2DCellsFromEdges(double eps, const MEDCouplingUMesh *m1, const int *desc1, const int *descIndx1,
10064 const std::vector<std::vector<int> >& intesctEdges1, const std::vector< std::vector<int> >& colinear2,
10065 const MEDCouplingUMesh *m2, const int *desc2, const int *descIndx2, const std::vector<std::vector<int> >& intesctEdges2,
10066 const std::vector<double>& addCoords,
10067 std::vector<double>& addCoordsQuadratic, std::vector<int>& cr, std::vector<int>& crI, std::vector<int>& cNb1, std::vector<int>& cNb2)
10069 static const int SPACEDIM=2;
10070 const double *coo1(m1->getCoords()->getConstPointer());
10071 const int *conn1(m1->getNodalConnectivity()->getConstPointer()),*connI1(m1->getNodalConnectivityIndex()->getConstPointer());
10072 int offset1(m1->getNumberOfNodes());
10073 const double *coo2(m2->getCoords()->getConstPointer());
10074 const int *conn2(m2->getNodalConnectivity()->getConstPointer()),*connI2(m2->getNodalConnectivityIndex()->getConstPointer());
10075 int offset2(offset1+m2->getNumberOfNodes());
10076 int offset3(offset2+((int)addCoords.size())/2);
10077 MCAuto<DataArrayDouble> bbox1Arr(m1->getBoundingBoxForBBTree()),bbox2Arr(m2->getBoundingBoxForBBTree());
10078 const double *bbox1(bbox1Arr->begin()),*bbox2(bbox2Arr->begin());
10079 // Here a BBTree on 2D-cells, not on segments:
10080 BBTree<SPACEDIM,int> myTree(bbox2,0,0,m2->getNumberOfCells(),eps);
10081 int ncell1(m1->getNumberOfCells());
10083 for(int i=0;i<ncell1;i++)
10085 std::vector<int> candidates2;
10086 myTree.getIntersectingElems(bbox1+i*2*SPACEDIM,candidates2);
10087 std::map<INTERP_KERNEL::Node *,int> mapp;
10088 std::map<int,INTERP_KERNEL::Node *> mappRev;
10089 INTERP_KERNEL::QuadraticPolygon pol1;
10090 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn1[connI1[i]];
10091 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
10092 // Populate mapp and mappRev with nodes from the current cell (i) from mesh1 - this also builds the Node* objects:
10093 MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,/* output */mapp,mappRev);
10094 // pol1 is the full cell from mesh2, in QP format, with all the additional intersecting nodes.
10095 pol1.buildFromCrudeDataArray(mappRev,cm.isQuadratic(),conn1+connI1[i]+1,coo1,
10096 desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1);
10098 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
10099 std::set<INTERP_KERNEL::Edge *> edgesBoundary2;// store all edges that are on boundary of (pol2 intersect pol1) minus edges on pol1.
10100 INTERP_KERNEL::IteratorOnComposedEdge it1(&pol1);
10101 for(it1.first();!it1.finished();it1.next())
10102 edges1.insert(it1.current()->getPtr());
10104 std::map<int,std::vector<INTERP_KERNEL::ElementaryEdge *> > edgesIn2ForShare; // common edges
10105 std::vector<INTERP_KERNEL::QuadraticPolygon> pol2s(candidates2.size());
10107 for(std::vector<int>::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++,ii++)
10109 INTERP_KERNEL::NormalizedCellType typ2=(INTERP_KERNEL::NormalizedCellType)conn2[connI2[*it2]];
10110 const INTERP_KERNEL::CellModel& cm2=INTERP_KERNEL::CellModel::GetCellModel(typ2);
10111 // Complete mapping with elements coming from the current cell it2 in mesh2:
10112 MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,/* output */mapp,mappRev);
10113 // pol2 is the new QP in the final merged result.
10114 pol2s[ii].buildFromCrudeDataArray2(mappRev,cm2.isQuadratic(),conn2+connI2[*it2]+1,coo2,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,
10115 pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2, /* output */ edgesIn2ForShare);
10118 for(std::vector<int>::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++,ii++)
10120 INTERP_KERNEL::ComposedEdge::InitLocationsWithOther(pol1,pol2s[ii]);
10121 pol2s[ii].updateLocOfEdgeFromCrudeDataArray2(desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2);
10122 //MEDCouplingUMeshAssignOnLoc(pol1,pol2,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,colinear2);
10123 pol1.buildPartitionsAbs(pol2s[ii],edges1,edgesBoundary2,mapp,i,*it2,offset3,addCoordsQuadratic,cr,crI,cNb1,cNb2);
10125 // Deals with remaining (non-consumed) edges from m1: these are the edges that were never touched
10126 // by m2 but that we still want to keep in the final result.
10127 if(!edges1.empty())
10131 INTERP_KERNEL::QuadraticPolygon::ComputeResidual(pol1,edges1,edgesBoundary2,mapp,offset3,i,addCoordsQuadratic,cr,crI,cNb1,cNb2);
10133 catch(INTERP_KERNEL::Exception& e)
10135 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();
10136 throw INTERP_KERNEL::Exception(oss.str());
10139 for(std::map<int,INTERP_KERNEL::Node *>::const_iterator it=mappRev.begin();it!=mappRev.end();it++)
10140 (*it).second->decrRef();
10145 * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
10146 * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
10147 * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
10148 * The caller is to deal with the resulting DataArrayInt.
10149 * \throw If the coordinate array is not set.
10150 * \throw If the nodal connectivity of the cells is not defined.
10151 * \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
10152 * \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
10154 * \sa DataArrayInt::sortEachPairToMakeALinkedList
10156 DataArrayInt *MEDCouplingUMesh::orderConsecutiveCells1D() const
10158 checkFullyDefined();
10159 if(getMeshDimension()!=1)
10160 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
10162 // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
10163 MCAuto<DataArrayInt> _d(DataArrayInt::New()),_dI(DataArrayInt::New());
10164 MCAuto<DataArrayInt> _rD(DataArrayInt::New()),_rDI(DataArrayInt::New());
10165 MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
10166 const int *d(_d->getConstPointer()), *dI(_dI->getConstPointer());
10167 const int *rD(_rD->getConstPointer()), *rDI(_rDI->getConstPointer());
10168 MCAuto<DataArrayInt> _dsi(_rDI->deltaShiftIndex());
10169 const int * dsi(_dsi->getConstPointer());
10170 MCAuto<DataArrayInt> dsii = _dsi->findIdsNotInRange(0,3);
10172 if (dsii->getNumberOfTuples())
10173 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
10175 int nc(getNumberOfCells());
10176 MCAuto<DataArrayInt> result(DataArrayInt::New());
10177 result->alloc(nc,1);
10179 // set of edges not used so far
10180 std::set<int> edgeSet;
10181 for (int i=0; i<nc; edgeSet.insert(i), i++);
10185 // while we have points with only one neighbor segments
10188 std::list<int> linePiece;
10189 // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
10190 for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
10192 // Fill the list forward (resp. backward) from the start segment:
10193 int activeSeg = startSeg;
10194 int prevPointId = -20;
10196 while (!edgeSet.empty())
10198 if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
10201 linePiece.push_back(activeSeg);
10203 linePiece.push_front(activeSeg);
10204 edgeSet.erase(activeSeg);
10207 int ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
10208 ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
10209 if (dsi[ptId] == 1) // hitting the end of the line
10211 prevPointId = ptId;
10212 int seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
10213 activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
10216 // Done, save final piece into DA:
10217 std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
10218 newIdx += linePiece.size();
10220 // identify next valid start segment (one which is not consumed)
10221 if(!edgeSet.empty())
10222 startSeg = *(edgeSet.begin());
10224 while (!edgeSet.empty());
10225 return result.retn();
10230 void IKGeo2DInternalMapper2(INTERP_KERNEL::Node *n, const std::map<MCAuto<INTERP_KERNEL::Node>,int>& m, int forbVal0, int forbVal1, std::vector<int>& isect)
10232 MCAuto<INTERP_KERNEL::Node> nTmp(n); nTmp->incrRef();
10233 std::map<MCAuto<INTERP_KERNEL::Node>,int>::const_iterator it(m.find(nTmp));
10235 throw INTERP_KERNEL::Exception("Internal error in remapping !");
10236 int v((*it).second);
10237 if(v==forbVal0 || v==forbVal1)
10239 if(std::find(isect.begin(),isect.end(),v)==isect.end())
10240 isect.push_back(v);
10243 bool IKGeo2DInternalMapper(const INTERP_KERNEL::ComposedEdge& c, const std::map<MCAuto<INTERP_KERNEL::Node>,int>& m, int forbVal0, int forbVal1, std::vector<int>& isect)
10248 bool presenceOfOn(false);
10249 for(int i=0;i<sz;i++)
10251 INTERP_KERNEL::ElementaryEdge *e(c[i]);
10252 if(e->getLoc()!=INTERP_KERNEL::FULL_ON_1)
10254 IKGeo2DInternalMapper2(e->getStartNode(),m,forbVal0,forbVal1,isect);
10255 IKGeo2DInternalMapper2(e->getEndNode(),m,forbVal0,forbVal1,isect);
10257 return presenceOfOn;
10263 * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
10264 * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
10265 * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
10266 * a minimal creation of new nodes is wanted.
10267 * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
10268 * nodes if a SEG3 is split without information of middle.
10269 * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
10270 * avoid to have a non conform mesh.
10272 * \return int - the number of new nodes created (in most of cases 0).
10274 * \throw If \a this is not coherent.
10275 * \throw If \a this has not spaceDim equal to 2.
10276 * \throw If \a this has not meshDim equal to 2.
10277 * \throw If some subcells needed to be split are orphan.
10278 * \sa MEDCouplingUMesh::conformize2D
10280 int MEDCouplingUMesh::split2DCells(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *midOpt, const DataArrayInt *midOptI)
10282 if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
10283 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
10284 desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
10285 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10286 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10287 if(midOpt==0 && midOptI==0)
10289 split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
10292 else if(midOpt!=0 && midOptI!=0)
10293 return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
10295 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
10299 * \b WARNING this method is \b potentially \b non \b const (if returned array is empty).
10300 * \b WARNING this method lead to have a non geometric type sorted mesh (for MED file users) !
10301 * 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
10302 * 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).
10303 * 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.
10305 * Whatever the returned value, this method does not alter the order of cells in \a this neither the orientation of cells.
10306 * The modified cells, if any, are systematically declared as NORM_POLYGON or NORM_QPOLYG depending on the initial quadraticness of geometric type.
10308 * This method expects that \b this has a meshDim equal 2 and spaceDim equal to 2 too.
10309 * This method expects that all nodes in \a this are not closer than \a eps.
10310 * If it is not the case you can invoke MEDCouplingUMesh::mergeNodes before calling this method.
10312 * \param [in] eps the relative error to detect merged edges.
10313 * \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
10314 * that the user is expected to deal with.
10316 * \throw If \a this is not coherent.
10317 * \throw If \a this has not spaceDim equal to 2.
10318 * \throw If \a this has not meshDim equal to 2.
10319 * \sa MEDCouplingUMesh::mergeNodes, MEDCouplingUMesh::split2DCells
10321 DataArrayInt *MEDCouplingUMesh::conformize2D(double eps)
10323 static const int SPACEDIM=2;
10324 checkConsistencyLight();
10325 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10326 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::conformize2D : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10327 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
10328 MCAuto<MEDCouplingUMesh> mDesc(buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));
10329 const int *c(mDesc->getNodalConnectivity()->getConstPointer()),*ci(mDesc->getNodalConnectivityIndex()->getConstPointer()),*rd(revDesc1->getConstPointer()),*rdi(revDescIndx1->getConstPointer());
10330 MCAuto<DataArrayDouble> bboxArr(mDesc->getBoundingBoxForBBTree());
10331 const double *bbox(bboxArr->begin()),*coords(getCoords()->begin());
10332 int nCell(getNumberOfCells()),nDescCell(mDesc->getNumberOfCells());
10333 std::vector< std::vector<int> > intersectEdge(nDescCell),overlapEdge(nDescCell);
10334 std::vector<double> addCoo;
10335 BBTree<SPACEDIM,int> myTree(bbox,0,0,nDescCell,-eps);
10336 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10337 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10338 for(int i=0;i<nDescCell;i++)
10340 std::vector<int> candidates;
10341 myTree.getIntersectingElems(bbox+i*2*SPACEDIM,candidates);
10342 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
10345 std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
10346 INTERP_KERNEL::Edge *e1(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coords,m)),
10347 *e2(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[*it]],c+ci[*it]+1,coords,m));
10348 INTERP_KERNEL::MergePoints merge;
10349 INTERP_KERNEL::QuadraticPolygon c1,c2;
10350 e1->intersectWith(e2,merge,c1,c2);
10351 e1->decrRef(); e2->decrRef();
10352 if(IKGeo2DInternalMapper(c1,m,c[ci[i]+1],c[ci[i]+2],intersectEdge[i]))
10353 overlapEdge[i].push_back(*it);
10354 if(IKGeo2DInternalMapper(c2,m,c[ci[*it]+1],c[ci[*it]+2],intersectEdge[*it]))
10355 overlapEdge[*it].push_back(i);
10358 // splitting done. sort intersect point in intersectEdge.
10359 std::vector< std::vector<int> > middle(nDescCell);
10360 int nbOf2DCellsToBeSplit(0);
10361 bool middleNeedsToBeUsed(false);
10362 std::vector<bool> cells2DToTreat(nDescCell,false);
10363 for(int i=0;i<nDescCell;i++)
10365 std::vector<int>& isect(intersectEdge[i]);
10366 int sz((int)isect.size());
10369 std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
10370 INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coords,m));
10371 e->sortSubNodesAbs(coords,isect);
10376 int idx0(rdi[i]),idx1(rdi[i+1]);
10378 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::conformize2D : internal error #0 !");
10379 if(!cells2DToTreat[rd[idx0]])
10381 cells2DToTreat[rd[idx0]]=true;
10382 nbOf2DCellsToBeSplit++;
10384 // try to reuse at most eventual 'middle' of SEG3
10385 std::vector<int>& mid(middle[i]);
10386 mid.resize(sz+1,-1);
10387 if((INTERP_KERNEL::NormalizedCellType)c[ci[i]]==INTERP_KERNEL::NORM_SEG3)
10389 middleNeedsToBeUsed=true;
10390 const std::vector<int>& candidates(overlapEdge[i]);
10391 std::vector<int> trueCandidates;
10392 for(std::vector<int>::const_iterator itc=candidates.begin();itc!=candidates.end();itc++)
10393 if((INTERP_KERNEL::NormalizedCellType)c[ci[*itc]]==INTERP_KERNEL::NORM_SEG3)
10394 trueCandidates.push_back(*itc);
10395 int stNode(c[ci[i]+1]),endNode(isect[0]);
10396 for(int j=0;j<sz+1;j++)
10398 for(std::vector<int>::const_iterator itc=trueCandidates.begin();itc!=trueCandidates.end();itc++)
10400 int tmpSt(c[ci[*itc]+1]),tmpEnd(c[ci[*itc]+2]);
10401 if((tmpSt==stNode && tmpEnd==endNode) || (tmpSt==endNode && tmpEnd==stNode))
10402 { mid[j]=*itc; break; }
10405 endNode=j<sz-1?isect[j+1]:c[ci[i]+2];
10410 MCAuto<DataArrayInt> ret(DataArrayInt::New()),notRet(DataArrayInt::New()); ret->alloc(nbOf2DCellsToBeSplit,1);
10411 if(nbOf2DCellsToBeSplit==0)
10414 int *retPtr(ret->getPointer());
10415 for(int i=0;i<nCell;i++)
10416 if(cells2DToTreat[i])
10419 MCAuto<DataArrayInt> mSafe,nSafe,oSafe,pSafe,qSafe,rSafe;
10420 DataArrayInt *m(0),*n(0),*o(0),*p(0),*q(0),*r(0);
10421 MEDCouplingUMesh::ExtractFromIndexedArrays(ret->begin(),ret->end(),desc1,descIndx1,m,n); mSafe=m; nSafe=n;
10422 DataArrayInt::PutIntoToSkylineFrmt(intersectEdge,o,p); oSafe=o; pSafe=p;
10423 if(middleNeedsToBeUsed)
10424 { DataArrayInt::PutIntoToSkylineFrmt(middle,q,r); qSafe=q; rSafe=r; }
10425 MCAuto<MEDCouplingUMesh> modif(static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(ret->begin(),ret->end(),true)));
10426 int nbOfNodesCreated(modif->split2DCells(mSafe,nSafe,oSafe,pSafe,qSafe,rSafe));
10427 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.
10428 setPartOfMySelf(ret->begin(),ret->end(),*modif);
10430 bool areNodesMerged; int newNbOfNodes;
10431 if(nbOfNodesCreated!=0)
10432 MCAuto<DataArrayInt> tmp(mergeNodes(eps,areNodesMerged,newNbOfNodes));
10438 * 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.
10439 * 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).
10440 * 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
10441 * to invoke MEDCouplingUMesh::mergeNodes and MEDCouplingUMesh::conformize2D right after this call.
10442 * 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
10443 * new nodes for center of merged edges is are systematically created and appended at the end of the previously existing nodes.
10445 * 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
10446 * using new instance, idem for coordinates.
10448 * 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.
10450 * \return DataArrayInt * - The list of cellIds in \a this that have at least one edge colinearized.
10452 * \throw If \a this is not coherent.
10453 * \throw If \a this has not spaceDim equal to 2.
10454 * \throw If \a this has not meshDim equal to 2.
10456 * \sa MEDCouplingUMesh::conformize2D, MEDCouplingUMesh::mergeNodes, MEDCouplingUMesh::convexEnvelop2D.
10458 DataArrayInt *MEDCouplingUMesh::colinearize2D(double eps)
10460 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
10461 checkConsistencyLight();
10462 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10463 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::colinearize2D : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10464 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10465 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10466 int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
10467 const int *cptr(_nodal_connec->begin()),*ciptr(_nodal_connec_index->begin());
10468 MCAuto<DataArrayInt> newc(DataArrayInt::New()),newci(DataArrayInt::New()); newci->alloc(nbOfCells+1,1); newc->alloc(0,1); newci->setIJ(0,0,0);
10469 MCAuto<DataArrayDouble> appendedCoords(DataArrayDouble::New()); appendedCoords->alloc(0,1);//1 not 2 it is not a bug.
10470 const double *coords(_coords->begin());
10471 int *newciptr(newci->getPointer());
10472 for(int i=0;i<nbOfCells;i++,newciptr++,ciptr++)
10474 if(Colinearize2DCell(coords,cptr+ciptr[0],cptr+ciptr[1],nbOfNodes,newc,appendedCoords))
10475 ret->pushBackSilent(i);
10476 newciptr[1]=newc->getNumberOfTuples();
10481 if(!appendedCoords->empty())
10483 appendedCoords->rearrange(2);
10484 MCAuto<DataArrayDouble> newCoords(DataArrayDouble::Aggregate(getCoords(),appendedCoords));//treat info on components
10486 setCoords(newCoords);
10489 setConnectivity(newc,newci,true);
10494 * \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.
10495 * 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.
10496 * And for each j in [1,n) intersect[i][2*(j-1)+1]==intersect[i][2*j].
10497 * \param [out] subDiv2 - for each cell in \a m2Desc returns nodes that split it using convention \a m1Desc first, then \a m2Desc, then addCoo
10498 * \param [out] colinear2 - for each cell in \a m2Desc returns the edges in \a m1Desc that are colinear to it.
10499 * \param [out] addCoo - nodes to be append at the end
10500 * \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.
10502 void MEDCouplingUMesh::Intersect1DMeshes(const MEDCouplingUMesh *m1Desc, const MEDCouplingUMesh *m2Desc, double eps,
10503 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)
10505 static const int SPACEDIM=2;
10506 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10507 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10508 const int *c1(m1Desc->getNodalConnectivity()->getConstPointer()),*ci1(m1Desc->getNodalConnectivityIndex()->getConstPointer());
10509 // Build BB tree of all edges in the tool mesh (second mesh)
10510 MCAuto<DataArrayDouble> bbox1Arr(m1Desc->getBoundingBoxForBBTree()),bbox2Arr(m2Desc->getBoundingBoxForBBTree());
10511 const double *bbox1(bbox1Arr->begin()),*bbox2(bbox2Arr->begin());
10512 int nDescCell1(m1Desc->getNumberOfCells()),nDescCell2(m2Desc->getNumberOfCells());
10513 intersectEdge1.resize(nDescCell1);
10514 colinear2.resize(nDescCell2);
10515 subDiv2.resize(nDescCell2);
10516 BBTree<SPACEDIM,int> myTree(bbox2,0,0,m2Desc->getNumberOfCells(),-eps);
10518 std::vector<int> candidates1(1);
10519 int offset1(m1Desc->getNumberOfNodes());
10520 int offset2(offset1+m2Desc->getNumberOfNodes());
10521 for(int i=0;i<nDescCell1;i++) // for all edges in the first mesh
10523 std::vector<int> candidates2; // edges of mesh2 candidate for intersection
10524 myTree.getIntersectingElems(bbox1+i*2*SPACEDIM,candidates2);
10525 if(!candidates2.empty()) // candidates2 holds edges from the second mesh potentially intersecting current edge i in mesh1
10527 std::map<INTERP_KERNEL::Node *,int> map1,map2;
10528 // pol2 is not necessarily a closed polygon: just a set of (quadratic) edges (same as candidates2) in the Geometric DS format
10529 INTERP_KERNEL::QuadraticPolygon *pol2=MEDCouplingUMeshBuildQPFromMesh(m2Desc,candidates2,map2);
10531 INTERP_KERNEL::QuadraticPolygon *pol1=MEDCouplingUMeshBuildQPFromMesh(m1Desc,candidates1,map1);
10532 // 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
10533 // This trick guarantees that Node * are discriminant (i.e. form a unique identifier)
10534 std::set<INTERP_KERNEL::Node *> nodes;
10535 pol1->getAllNodes(nodes); pol2->getAllNodes(nodes);
10536 std::size_t szz(nodes.size());
10537 std::vector< MCAuto<INTERP_KERNEL::Node> > nodesSafe(szz);
10538 std::set<INTERP_KERNEL::Node *>::const_iterator itt(nodes.begin());
10539 for(std::size_t iii=0;iii<szz;iii++,itt++)
10540 { (*itt)->incrRef(); nodesSafe[iii]=*itt; }
10541 // end of protection
10542 // Performs egde cutting:
10543 pol1->splitAbs(*pol2,map1,map2,offset1,offset2,candidates2,intersectEdge1[i],i,colinear2,subDiv2,addCoo,mergedNodes);
10548 // Copy the edge (take only the two first points, ie discard quadratic point at this stage)
10549 intersectEdge1[i].insert(intersectEdge1[i].end(),c1+ci1[i]+1,c1+ci1[i]+3);
10554 * This method is private and is the first step of Partition of 2D mesh (spaceDim==2 and meshDim==2).
10555 * It builds the descending connectivity of the two meshes, and then using a binary tree
10556 * it computes the edge intersections. This results in new points being created : they're stored in addCoo.
10557 * Documentation about parameters colinear2 and subDiv2 can be found in method QuadraticPolygon::splitAbs().
10559 void MEDCouplingUMesh::IntersectDescending2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2, double eps,
10560 std::vector< std::vector<int> >& intersectEdge1, std::vector< std::vector<int> >& colinear2, std::vector< std::vector<int> >& subDiv2,
10561 MEDCouplingUMesh *& m1Desc, DataArrayInt *&desc1, DataArrayInt *&descIndx1, DataArrayInt *&revDesc1, DataArrayInt *&revDescIndx1,
10562 std::vector<double>& addCoo,
10563 MEDCouplingUMesh *& m2Desc, DataArrayInt *&desc2, DataArrayInt *&descIndx2, DataArrayInt *&revDesc2, DataArrayInt *&revDescIndx2)
10565 // Build desc connectivity
10566 desc1=DataArrayInt::New(); descIndx1=DataArrayInt::New(); revDesc1=DataArrayInt::New(); revDescIndx1=DataArrayInt::New();
10567 desc2=DataArrayInt::New();
10568 descIndx2=DataArrayInt::New();
10569 revDesc2=DataArrayInt::New();
10570 revDescIndx2=DataArrayInt::New();
10571 MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(revDesc1),dd4(revDescIndx1);
10572 MCAuto<DataArrayInt> dd5(desc2),dd6(descIndx2),dd7(revDesc2),dd8(revDescIndx2);
10573 m1Desc=m1->buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1);
10574 m2Desc=m2->buildDescendingConnectivity2(desc2,descIndx2,revDesc2,revDescIndx2);
10575 MCAuto<MEDCouplingUMesh> dd9(m1Desc),dd10(m2Desc);
10576 std::map<int,int> notUsedMap;
10577 Intersect1DMeshes(m1Desc,m2Desc,eps,intersectEdge1,colinear2,subDiv2,addCoo,notUsedMap);
10578 m1Desc->incrRef(); desc1->incrRef(); descIndx1->incrRef(); revDesc1->incrRef(); revDescIndx1->incrRef();
10579 m2Desc->incrRef(); desc2->incrRef(); descIndx2->incrRef(); revDesc2->incrRef(); revDescIndx2->incrRef();
10583 * This method performs the 2nd step of Partition of 2D mesh.
10584 * This method has 4 inputs :
10585 * - a mesh 'm1' with meshDim==1 and a SpaceDim==2
10586 * - a mesh 'm2' with meshDim==1 and a SpaceDim==2
10587 * - subDiv of size 'm2->getNumberOfCells()' that lists for each seg cell in 'm' the splitting node ids randomly sorted.
10588 * 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'
10589 * Nodes end up lying consecutively on a cutted edge.
10590 * \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.
10591 * (Only present for its coords in case of 'subDiv' shares some nodes of 'm1')
10592 * \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.
10593 * \param addCoo input parameter with additional nodes linked to intersection of the 2 meshes.
10594 * \param[out] intersectEdge the same content as subDiv, but correclty oriented.
10596 void MEDCouplingUMesh::BuildIntersectEdges(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2,
10597 const std::vector<double>& addCoo,
10598 const std::vector< std::vector<int> >& subDiv, std::vector< std::vector<int> >& intersectEdge)
10600 int offset1=m1->getNumberOfNodes();
10601 int ncell=m2->getNumberOfCells();
10602 const int *c=m2->getNodalConnectivity()->getConstPointer();
10603 const int *cI=m2->getNodalConnectivityIndex()->getConstPointer();
10604 const double *coo=m2->getCoords()->getConstPointer();
10605 const double *cooBis=m1->getCoords()->getConstPointer();
10606 int offset2=offset1+m2->getNumberOfNodes();
10607 intersectEdge.resize(ncell);
10608 for(int i=0;i<ncell;i++,cI++)
10610 const std::vector<int>& divs=subDiv[i];
10611 int nnode=cI[1]-cI[0]-1;
10612 std::map<int, std::pair<INTERP_KERNEL::Node *,bool> > mapp2;
10613 std::map<INTERP_KERNEL::Node *, int> mapp22;
10614 for(int j=0;j<nnode;j++)
10616 INTERP_KERNEL::Node *nn=new INTERP_KERNEL::Node(coo[2*c[(*cI)+j+1]],coo[2*c[(*cI)+j+1]+1]);
10617 int nnid=c[(*cI)+j+1];
10618 mapp2[nnid]=std::pair<INTERP_KERNEL::Node *,bool>(nn,true);
10619 mapp22[nn]=nnid+offset1;
10621 INTERP_KERNEL::Edge *e=MEDCouplingUMeshBuildQPFromEdge((INTERP_KERNEL::NormalizedCellType)c[*cI],mapp2,c+(*cI)+1);
10622 for(std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >::const_iterator it=mapp2.begin();it!=mapp2.end();it++)
10623 ((*it).second.first)->decrRef();
10624 std::vector<INTERP_KERNEL::Node *> addNodes(divs.size());
10625 std::map<INTERP_KERNEL::Node *,int> mapp3;
10626 for(std::size_t j=0;j<divs.size();j++)
10629 INTERP_KERNEL::Node *tmp=0;
10631 tmp=new INTERP_KERNEL::Node(cooBis[2*id],cooBis[2*id+1]);
10632 else if(id<offset2)
10633 tmp=new INTERP_KERNEL::Node(coo[2*(id-offset1)],coo[2*(id-offset1)+1]);//if it happens, bad news mesh 'm2' is non conform.
10635 tmp=new INTERP_KERNEL::Node(addCoo[2*(id-offset2)],addCoo[2*(id-offset2)+1]);
10639 e->sortIdsAbs(addNodes,mapp22,mapp3,intersectEdge[i]);
10640 for(std::vector<INTERP_KERNEL::Node *>::const_iterator it=addNodes.begin();it!=addNodes.end();it++)
10647 * 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).
10648 * 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
10649 * with a plane. The result will be put in 'cut3DSuf' out parameter.
10650 * \param [in] cut3DCurve input paramter that gives for each 3DCurve cell if it owns fully to the plane or partially.
10651 * \param [out] nodesOnPlane, returns all the nodes that are on the plane.
10652 * \param [in] nodal3DSurf is the nodal connectivity of 3D surf mesh.
10653 * \param [in] nodalIndx3DSurf is the nodal connectivity index of 3D surf mesh.
10654 * \param [in] nodal3DCurve is the nodal connectivity of 3D curve mesh.
10655 * \param [in] nodal3DIndxCurve is the nodal connectivity index of 3D curve mesh.
10656 * \param [in] desc is the descending connectivity 3DSurf->3DCurve
10657 * \param [in] descIndx is the descending connectivity index 3DSurf->3DCurve
10658 * \param [out] cut3DSuf input/output param.
10660 void MEDCouplingUMesh::AssemblyForSplitFrom3DCurve(const std::vector<int>& cut3DCurve, std::vector<int>& nodesOnPlane, const int *nodal3DSurf, const int *nodalIndx3DSurf,
10661 const int *nodal3DCurve, const int *nodalIndx3DCurve,
10662 const int *desc, const int *descIndx,
10663 std::vector< std::pair<int,int> >& cut3DSurf)
10665 std::set<int> nodesOnP(nodesOnPlane.begin(),nodesOnPlane.end());
10666 int nbOf3DSurfCell=(int)cut3DSurf.size();
10667 for(int i=0;i<nbOf3DSurfCell;i++)
10669 std::vector<int> res;
10670 int offset=descIndx[i];
10671 int nbOfSeg=descIndx[i+1]-offset;
10672 for(int j=0;j<nbOfSeg;j++)
10674 int edgeId=desc[offset+j];
10675 int status=cut3DCurve[edgeId];
10679 res.push_back(status);
10682 res.push_back(nodal3DCurve[nodalIndx3DCurve[edgeId]+1]);
10683 res.push_back(nodal3DCurve[nodalIndx3DCurve[edgeId]+2]);
10691 cut3DSurf[i].first=res[0]; cut3DSurf[i].second=res[1];
10697 std::set<int> s1(nodal3DSurf+nodalIndx3DSurf[i]+1,nodal3DSurf+nodalIndx3DSurf[i+1]);
10698 std::set_intersection(nodesOnP.begin(),nodesOnP.end(),s1.begin(),s1.end(),std::back_insert_iterator< std::vector<int> >(res));
10701 cut3DSurf[i].first=res[0]; cut3DSurf[i].second=res[1];
10705 cut3DSurf[i].first=-1; cut3DSurf[i].second=-1;
10710 {// case when plane is on a multi colinear edge of a polyhedron
10711 if((int)res.size()==2*nbOfSeg)
10713 cut3DSurf[i].first=-2; cut3DSurf[i].second=i;
10716 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AssemblyPointsFrom3DCurve : unexpected situation !");
10723 * \a this is expected to be a mesh with spaceDim==3 and meshDim==3. If not an exception will be thrown.
10724 * 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).
10725 * 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
10726 * with a plane. The result will be put in 'nodalRes' 'nodalResIndx' and 'cellIds' out parameters.
10727 * \param cut3DSurf input paramter that gives for each 3DSurf its intersection with plane (result of MEDCouplingUMesh::AssemblyForSplitFrom3DCurve).
10728 * \param desc is the descending connectivity 3D->3DSurf
10729 * \param descIndx is the descending connectivity index 3D->3DSurf
10731 void MEDCouplingUMesh::assemblyForSplitFrom3DSurf(const std::vector< std::pair<int,int> >& cut3DSurf,
10732 const int *desc, const int *descIndx,
10733 DataArrayInt *nodalRes, DataArrayInt *nodalResIndx, DataArrayInt *cellIds) const
10735 checkFullyDefined();
10736 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
10737 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::assemblyForSplitFrom3DSurf works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
10738 const int *nodal3D=_nodal_connec->getConstPointer();
10739 const int *nodalIndx3D=_nodal_connec_index->getConstPointer();
10740 int nbOfCells=getNumberOfCells();
10741 for(int i=0;i<nbOfCells;i++)
10743 std::map<int, std::set<int> > m;
10744 int offset=descIndx[i];
10745 int nbOfFaces=descIndx[i+1]-offset;
10748 for(int j=0;j<nbOfFaces;j++)
10750 const std::pair<int,int>& p=cut3DSurf[desc[offset+j]];
10751 if(p.first!=-1 && p.second!=-1)
10755 start=p.first; end=p.second;
10756 m[p.first].insert(p.second);
10757 m[p.second].insert(p.first);
10761 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodal3D[nodalIndx3D[i]]);
10762 int sz=nodalIndx3D[i+1]-nodalIndx3D[i]-1;
10763 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
10764 INTERP_KERNEL::NormalizedCellType cmsId;
10765 unsigned nbOfNodesSon=cm.fillSonCellNodalConnectivity2(j,nodal3D+nodalIndx3D[i]+1,sz,tmp,cmsId);
10766 start=tmp[0]; end=tmp[nbOfNodesSon-1];
10767 for(unsigned k=0;k<nbOfNodesSon;k++)
10769 m[tmp[k]].insert(tmp[(k+1)%nbOfNodesSon]);
10770 m[tmp[(k+1)%nbOfNodesSon]].insert(tmp[k]);
10777 std::vector<int> conn(1,(int)INTERP_KERNEL::NORM_POLYGON);
10781 std::map<int, std::set<int> >::const_iterator it=m.find(start);
10782 const std::set<int>& s=(*it).second;
10783 std::set<int> s2; s2.insert(prev);
10785 std::set_difference(s.begin(),s.end(),s2.begin(),s2.end(),inserter(s3,s3.begin()));
10788 int val=*s3.begin();
10789 conn.push_back(start);
10796 conn.push_back(end);
10799 nodalRes->insertAtTheEnd(conn.begin(),conn.end());
10800 nodalResIndx->pushBackSilent(nodalRes->getNumberOfTuples());
10801 cellIds->pushBackSilent(i);
10807 * 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
10808 * 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
10809 * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
10810 * 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
10811 * 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.
10813 * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
10815 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const int *nodalConnBg, const int *nodalConnEnd, DataArrayInt *nodalConnecOut)
10817 std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
10820 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
10821 if(cm.getDimension()==2)
10823 const int *node=nodalConnBg+1;
10824 int startNode=*node++;
10825 double refX=coords[2*startNode];
10826 for(;node!=nodalConnEnd;node++)
10828 if(coords[2*(*node)]<refX)
10831 refX=coords[2*startNode];
10834 std::vector<int> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
10838 double angle0=-M_PI/2;
10843 double angleNext=0.;
10844 while(nextNode!=startNode)
10848 for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
10850 if(*node!=tmpOut.back() && *node!=prevNode)
10852 tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
10853 double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
10858 res=angle0-angleM+2.*M_PI;
10867 if(nextNode!=startNode)
10869 angle0=angleNext-M_PI;
10872 prevNode=tmpOut.back();
10873 tmpOut.push_back(nextNode);
10876 std::vector<int> tmp3(2*(sz-1));
10877 std::vector<int>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
10878 std::copy(nodalConnBg+1,nodalConnEnd,it);
10879 if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
10881 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
10884 if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
10886 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
10891 nodalConnecOut->pushBackSilent((int)INTERP_KERNEL::NORM_POLYGON);
10892 nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
10897 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
10900 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
10904 * This method works on an input pair (\b arr, \b arrIndx) where \b arr indexes is in \b arrIndx.
10905 * 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.
10907 * \param [in] idsToRemoveBg begin of set of ids to remove in \b arr (included)
10908 * \param [in] idsToRemoveEnd end of set of ids to remove in \b arr (excluded)
10909 * \param [in,out] arr array in which the remove operation will be done.
10910 * \param [in,out] arrIndx array in the remove operation will modify
10911 * \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])
10912 * \return true if \b arr and \b arrIndx have been modified, false if not.
10914 bool MEDCouplingUMesh::RemoveIdsFromIndexedArrays(const int *idsToRemoveBg, const int *idsToRemoveEnd, DataArrayInt *arr, DataArrayInt *arrIndx, int offsetForRemoval)
10916 if(!arrIndx || !arr)
10917 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : some input arrays are empty !");
10918 if(offsetForRemoval<0)
10919 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : offsetForRemoval should be >=0 !");
10920 std::set<int> s(idsToRemoveBg,idsToRemoveEnd);
10921 int nbOfGrps=arrIndx->getNumberOfTuples()-1;
10922 int *arrIPtr=arrIndx->getPointer();
10924 int previousArrI=0;
10925 const int *arrPtr=arr->getConstPointer();
10926 std::vector<int> arrOut;//no utility to switch to DataArrayInt because copy always needed
10927 for(int i=0;i<nbOfGrps;i++,arrIPtr++)
10929 if(*arrIPtr-previousArrI>offsetForRemoval)
10931 for(const int *work=arrPtr+previousArrI+offsetForRemoval;work!=arrPtr+*arrIPtr;work++)
10933 if(s.find(*work)==s.end())
10934 arrOut.push_back(*work);
10937 previousArrI=*arrIPtr;
10938 *arrIPtr=(int)arrOut.size();
10940 if(arr->getNumberOfTuples()==(int)arrOut.size())
10942 arr->alloc((int)arrOut.size(),1);
10943 std::copy(arrOut.begin(),arrOut.end(),arr->getPointer());
10948 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
10949 * (\ref numbering-indirect).
10950 * This method returns the result of the extraction ( specified by a set of ids in [\b idsOfSelectBg , \b idsOfSelectEnd ) ).
10951 * The selection of extraction is done standardly in new2old format.
10952 * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
10954 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
10955 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
10956 * \param [in] arrIn arr origin array from which the extraction will be done.
10957 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
10958 * \param [out] arrOut the resulting array
10959 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
10960 * \sa MEDCouplingUMesh::ExtractFromIndexedArraysSlice
10962 void MEDCouplingUMesh::ExtractFromIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
10963 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
10965 if(!arrIn || !arrIndxIn)
10966 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input pointer is NULL !");
10967 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
10968 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
10969 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input arrays must have exactly one component !");
10970 std::size_t sz=std::distance(idsOfSelectBg,idsOfSelectEnd);
10971 const int *arrInPtr=arrIn->getConstPointer();
10972 const int *arrIndxPtr=arrIndxIn->getConstPointer();
10973 int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
10975 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
10976 int maxSizeOfArr=arrIn->getNumberOfTuples();
10977 MCAuto<DataArrayInt> arro=DataArrayInt::New();
10978 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
10979 arrIo->alloc((int)(sz+1),1);
10980 const int *idsIt=idsOfSelectBg;
10981 int *work=arrIo->getPointer();
10984 for(std::size_t i=0;i<sz;i++,work++,idsIt++)
10986 if(*idsIt>=0 && *idsIt<nbOfGrps)
10987 lgth+=arrIndxPtr[*idsIt+1]-arrIndxPtr[*idsIt];
10990 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " ! Must be in [0," << nbOfGrps << ") !";
10991 throw INTERP_KERNEL::Exception(oss.str());
10997 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " and at this pos arrIndxIn[" << *idsIt;
10998 oss << "+1]-arrIndxIn[" << *idsIt << "] < 0 ! The input index array is bugged !";
10999 throw INTERP_KERNEL::Exception(oss.str());
11002 arro->alloc(lgth,1);
11003 work=arro->getPointer();
11004 idsIt=idsOfSelectBg;
11005 for(std::size_t i=0;i<sz;i++,idsIt++)
11007 if(arrIndxPtr[*idsIt]>=0 && arrIndxPtr[*idsIt+1]<=maxSizeOfArr)
11008 work=std::copy(arrInPtr+arrIndxPtr[*idsIt],arrInPtr+arrIndxPtr[*idsIt+1],work);
11011 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " arrIndx[" << *idsIt << "] must be >= 0 and arrIndx[";
11012 oss << *idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
11013 throw INTERP_KERNEL::Exception(oss.str());
11016 arrOut=arro.retn();
11017 arrIndexOut=arrIo.retn();
11021 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
11022 * (\ref numbering-indirect).
11023 * 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 ).
11024 * The selection of extraction is done standardly in new2old format.
11025 * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
11027 * \param [in] idsOfSelectStart begin of set of ids of the input extraction (included)
11028 * \param [in] idsOfSelectStop end of set of ids of the input extraction (excluded)
11029 * \param [in] idsOfSelectStep
11030 * \param [in] arrIn arr origin array from which the extraction will be done.
11031 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11032 * \param [out] arrOut the resulting array
11033 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11034 * \sa MEDCouplingUMesh::ExtractFromIndexedArrays
11036 void MEDCouplingUMesh::ExtractFromIndexedArraysSlice(int idsOfSelectStart, int idsOfSelectStop, int idsOfSelectStep, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11037 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11039 if(!arrIn || !arrIndxIn)
11040 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input pointer is NULL !");
11041 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
11042 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
11043 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input arrays must have exactly one component !");
11044 int sz=DataArrayInt::GetNumberOfItemGivenBESRelative(idsOfSelectStart,idsOfSelectStop,idsOfSelectStep,"MEDCouplingUMesh::ExtractFromIndexedArraysSlice : Input slice ");
11045 const int *arrInPtr=arrIn->getConstPointer();
11046 const int *arrIndxPtr=arrIndxIn->getConstPointer();
11047 int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
11049 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
11050 int maxSizeOfArr=arrIn->getNumberOfTuples();
11051 MCAuto<DataArrayInt> arro=DataArrayInt::New();
11052 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11053 arrIo->alloc((int)(sz+1),1);
11054 int idsIt=idsOfSelectStart;
11055 int *work=arrIo->getPointer();
11058 for(int i=0;i<sz;i++,work++,idsIt+=idsOfSelectStep)
11060 if(idsIt>=0 && idsIt<nbOfGrps)
11061 lgth+=arrIndxPtr[idsIt+1]-arrIndxPtr[idsIt];
11064 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " ! Must be in [0," << nbOfGrps << ") !";
11065 throw INTERP_KERNEL::Exception(oss.str());
11071 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " and at this pos arrIndxIn[" << idsIt;
11072 oss << "+1]-arrIndxIn[" << idsIt << "] < 0 ! The input index array is bugged !";
11073 throw INTERP_KERNEL::Exception(oss.str());
11076 arro->alloc(lgth,1);
11077 work=arro->getPointer();
11078 idsIt=idsOfSelectStart;
11079 for(int i=0;i<sz;i++,idsIt+=idsOfSelectStep)
11081 if(arrIndxPtr[idsIt]>=0 && arrIndxPtr[idsIt+1]<=maxSizeOfArr)
11082 work=std::copy(arrInPtr+arrIndxPtr[idsIt],arrInPtr+arrIndxPtr[idsIt+1],work);
11085 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " arrIndx[" << idsIt << "] must be >= 0 and arrIndx[";
11086 oss << idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
11087 throw INTERP_KERNEL::Exception(oss.str());
11090 arrOut=arro.retn();
11091 arrIndexOut=arrIo.retn();
11095 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11096 * 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
11097 * cellIds \b in [ \b idsOfSelectBg , \b idsOfSelectEnd ) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
11098 * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
11100 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
11101 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
11102 * \param [in] arrIn arr origin array from which the extraction will be done.
11103 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11104 * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg, \b idsOfSelectEnd )
11105 * \param [in] srcArrIndex index array of \b srcArr
11106 * \param [out] arrOut the resulting array
11107 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11109 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
11111 void MEDCouplingUMesh::SetPartOfIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11112 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
11113 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11115 if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11116 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArrays : presence of null pointer in input parameter !");
11117 MCAuto<DataArrayInt> arro=DataArrayInt::New();
11118 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11119 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11120 std::vector<bool> v(nbOfTuples,true);
11122 const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11123 const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11124 for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
11126 if(*it>=0 && *it<nbOfTuples)
11129 offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[*it+1]-arrIndxInPtr[*it]);
11133 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArrays : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
11134 throw INTERP_KERNEL::Exception(oss.str());
11137 srcArrIndexPtr=srcArrIndex->getConstPointer();
11138 arrIo->alloc(nbOfTuples+1,1);
11139 arro->alloc(arrIn->getNumberOfTuples()+offset,1);
11140 const int *arrInPtr=arrIn->getConstPointer();
11141 const int *srcArrPtr=srcArr->getConstPointer();
11142 int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
11143 int *arroPtr=arro->getPointer();
11144 for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
11148 arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
11149 *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
11153 std::size_t pos=std::distance(idsOfSelectBg,std::find(idsOfSelectBg,idsOfSelectEnd,ii));
11154 arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
11155 *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
11158 arrOut=arro.retn();
11159 arrIndexOut=arrIo.retn();
11163 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11164 * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
11166 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
11167 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
11168 * \param [in,out] arrInOut arr origin array from which the extraction will be done.
11169 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11170 * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg , \b idsOfSelectEnd )
11171 * \param [in] srcArrIndex index array of \b srcArr
11173 * \sa MEDCouplingUMesh::SetPartOfIndexedArrays
11175 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(const int *idsOfSelectBg, const int *idsOfSelectEnd, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
11176 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
11178 if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11179 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : presence of null pointer in input parameter !");
11180 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11181 const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11182 const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11183 int *arrInOutPtr=arrInOut->getPointer();
11184 const int *srcArrPtr=srcArr->getConstPointer();
11185 for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
11187 if(*it>=0 && *it<nbOfTuples)
11189 if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[*it+1]-arrIndxInPtr[*it])
11190 std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[*it]);
11193 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] !";
11194 throw INTERP_KERNEL::Exception(oss.str());
11199 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
11200 throw INTERP_KERNEL::Exception(oss.str());
11206 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
11207 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
11208 * 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]].
11209 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
11210 * A negative value in \b arrIn means that it is ignored.
11211 * 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.
11213 * \param [in] arrIn arr origin array from which the extraction will be done.
11214 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11215 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
11216 * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
11218 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn)
11220 int seed=0,nbOfDepthPeelingPerformed=0;
11221 return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
11225 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
11226 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
11227 * 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]].
11228 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
11229 * A negative value in \b arrIn means that it is ignored.
11230 * 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.
11231 * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
11232 * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
11233 * \param [in] arrIn arr origin array from which the extraction will be done.
11234 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11235 * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
11236 * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
11237 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
11238 * \sa MEDCouplingUMesh::partitionBySpreadZone
11240 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed)
11242 nbOfDepthPeelingPerformed=0;
11244 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
11245 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11248 DataArrayInt *ret=DataArrayInt::New(); ret->alloc(0,1);
11252 std::vector<bool> fetched(nbOfTuples,false);
11253 return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
11256 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg(std::vector<bool>& fetched, const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed)
11258 nbOfDepthPeelingPerformed=0;
11259 if(!seedBg || !seedEnd || !arrIn || !arrIndxIn)
11260 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg : some input pointer is NULL !");
11261 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11262 std::vector<bool> fetched2(nbOfTuples,false);
11264 for(const int *seedElt=seedBg;seedElt!=seedEnd;seedElt++,i++)
11266 if(*seedElt>=0 && *seedElt<nbOfTuples)
11267 { fetched[*seedElt]=true; fetched2[*seedElt]=true; }
11269 { 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()); }
11271 const int *arrInPtr=arrIn->getConstPointer();
11272 const int *arrIndxPtr=arrIndxIn->getConstPointer();
11273 int targetNbOfDepthPeeling=nbOfDepthPeeling!=-1?nbOfDepthPeeling:std::numeric_limits<int>::max();
11274 std::vector<int> idsToFetch1(seedBg,seedEnd);
11275 std::vector<int> idsToFetch2;
11276 std::vector<int> *idsToFetch=&idsToFetch1;
11277 std::vector<int> *idsToFetchOther=&idsToFetch2;
11278 while(!idsToFetch->empty() && nbOfDepthPeelingPerformed<targetNbOfDepthPeeling)
11280 for(std::vector<int>::const_iterator it=idsToFetch->begin();it!=idsToFetch->end();it++)
11281 for(const int *it2=arrInPtr+arrIndxPtr[*it];it2!=arrInPtr+arrIndxPtr[*it+1];it2++)
11283 { fetched[*it2]=true; fetched2[*it2]=true; idsToFetchOther->push_back(*it2); }
11284 std::swap(idsToFetch,idsToFetchOther);
11285 idsToFetchOther->clear();
11286 nbOfDepthPeelingPerformed++;
11288 int lgth=(int)std::count(fetched2.begin(),fetched2.end(),true);
11290 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(lgth,1);
11291 int *retPtr=ret->getPointer();
11292 for(std::vector<bool>::const_iterator it=fetched2.begin();it!=fetched2.end();it++,i++)
11299 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11300 * 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
11301 * cellIds \b in [\b idsOfSelectBg, \b idsOfSelectEnd) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
11302 * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
11304 * \param [in] start begin of set of ids of the input extraction (included)
11305 * \param [in] end end of set of ids of the input extraction (excluded)
11306 * \param [in] step step of the set of ids in range mode.
11307 * \param [in] arrIn arr origin array from which the extraction will be done.
11308 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11309 * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
11310 * \param [in] srcArrIndex index array of \b srcArr
11311 * \param [out] arrOut the resulting array
11312 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11314 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx MEDCouplingUMesh::SetPartOfIndexedArrays
11316 void MEDCouplingUMesh::SetPartOfIndexedArraysSlice(int start, int end, int step, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11317 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
11318 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11320 if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11321 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSlice : presence of null pointer in input parameter !");
11322 MCAuto<DataArrayInt> arro=DataArrayInt::New();
11323 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11324 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11326 const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11327 const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11328 int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSlice : ");
11330 for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
11332 if(it>=0 && it<nbOfTuples)
11333 offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[it+1]-arrIndxInPtr[it]);
11336 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
11337 throw INTERP_KERNEL::Exception(oss.str());
11340 srcArrIndexPtr=srcArrIndex->getConstPointer();
11341 arrIo->alloc(nbOfTuples+1,1);
11342 arro->alloc(arrIn->getNumberOfTuples()+offset,1);
11343 const int *arrInPtr=arrIn->getConstPointer();
11344 const int *srcArrPtr=srcArr->getConstPointer();
11345 int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
11346 int *arroPtr=arro->getPointer();
11347 for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
11349 int pos=DataArray::GetPosOfItemGivenBESRelativeNoThrow(ii,start,end,step);
11352 arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
11353 *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
11357 arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
11358 *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
11361 arrOut=arro.retn();
11362 arrIndexOut=arrIo.retn();
11366 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11367 * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
11369 * \param [in] start begin of set of ids of the input extraction (included)
11370 * \param [in] end end of set of ids of the input extraction (excluded)
11371 * \param [in] step step of the set of ids in range mode.
11372 * \param [in,out] arrInOut arr origin array from which the extraction will be done.
11373 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11374 * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
11375 * \param [in] srcArrIndex index array of \b srcArr
11377 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSlice MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
11379 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(int start, int end, int step, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
11380 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
11382 if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11383 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : presence of null pointer in input parameter !");
11384 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11385 const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11386 const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11387 int *arrInOutPtr=arrInOut->getPointer();
11388 const int *srcArrPtr=srcArr->getConstPointer();
11389 int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : ");
11391 for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
11393 if(it>=0 && it<nbOfTuples)
11395 if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[it+1]-arrIndxInPtr[it])
11396 std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[it]);
11399 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " id (idsOfSelectBg[" << i << "]) is " << it << " arrIndxIn[id+1]-arrIndxIn[id]!=srcArrIndex[pos+1]-srcArrIndex[pos] !";
11400 throw INTERP_KERNEL::Exception(oss.str());
11405 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
11406 throw INTERP_KERNEL::Exception(oss.str());
11412 * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
11413 * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
11414 * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
11415 * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
11416 * The sum of measure field of returned mesh is equal to the sum of measure field of this.
11418 * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
11420 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
11422 checkFullyDefined();
11423 int mdim=getMeshDimension();
11424 int spaceDim=getSpaceDimension();
11426 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
11427 std::vector<DataArrayInt *> partition=partitionBySpreadZone();
11428 std::vector< MCAuto<DataArrayInt> > partitionAuto; partitionAuto.reserve(partition.size());
11429 std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayInt> > >(partitionAuto));
11430 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
11431 ret->setCoords(getCoords());
11432 ret->allocateCells((int)partition.size());
11434 for(std::vector<DataArrayInt *>::const_iterator it=partition.begin();it!=partition.end();it++)
11436 MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
11437 MCAuto<DataArrayInt> cell;
11441 cell=tmp->buildUnionOf2DMesh();
11444 cell=tmp->buildUnionOf3DMesh();
11447 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
11450 ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->getConstPointer()+1);
11453 ret->finishInsertingCells();
11458 * This method partitions \b this into contiguous zone.
11459 * This method only needs a well defined connectivity. Coordinates are not considered here.
11460 * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
11462 std::vector<DataArrayInt *> MEDCouplingUMesh::partitionBySpreadZone() const
11464 int nbOfCellsCur=getNumberOfCells();
11465 std::vector<DataArrayInt *> ret;
11466 if(nbOfCellsCur<=0)
11468 DataArrayInt *neigh=0,*neighI=0;
11469 computeNeighborsOfCells(neigh,neighI);
11470 MCAuto<DataArrayInt> neighAuto(neigh),neighIAuto(neighI);
11471 std::vector<bool> fetchedCells(nbOfCellsCur,false);
11472 std::vector< MCAuto<DataArrayInt> > ret2;
11474 while(seed<nbOfCellsCur)
11476 int nbOfPeelPerformed=0;
11477 ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,neigh,neighI,-1,nbOfPeelPerformed));
11478 seed=(int)std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false));
11480 for(std::vector< MCAuto<DataArrayInt> >::iterator it=ret2.begin();it!=ret2.end();it++)
11481 ret.push_back((*it).retn());
11486 * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
11487 * newly allocated DataArrayInt instance with 2 components ready to be interpreted as input of DataArrayInt::findRangeIdForEachTuple method.
11489 * \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.
11490 * \return a newly allocated DataArrayInt to be managed by the caller.
11491 * \throw In case of \a code has not the right format (typically of size 3*n)
11493 DataArrayInt *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<int>& code)
11495 MCAuto<DataArrayInt> ret=DataArrayInt::New();
11496 std::size_t nb=code.size()/3;
11497 if(code.size()%3!=0)
11498 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
11499 ret->alloc((int)nb,2);
11500 int *retPtr=ret->getPointer();
11501 for(std::size_t i=0;i<nb;i++,retPtr+=2)
11503 retPtr[0]=code[3*i+2];
11504 retPtr[1]=code[3*i+2]+code[3*i+1];
11510 * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
11511 * All cells in \a this are expected to be linear 3D cells.
11512 * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
11513 * It leads to an increase to number of cells.
11514 * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
11515 * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
11516 * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
11518 * \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.
11519 * For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
11520 * \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.
11521 * \param [out] n2oCells - A new instance of DataArrayInt holding, for each new cell,
11522 * an id of old cell producing it. The caller is to delete this array using
11523 * decrRef() as it is no more needed.
11524 * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
11526 * \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
11527 * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
11529 * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
11530 * \throw If \a this is not fully constituted with linear 3D cells.
11531 * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
11533 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayInt *& n2oCells, int& nbOfAdditionalPoints) const
11535 INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
11536 checkConnectivityFullyDefined();
11537 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
11538 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
11539 int nbOfCells(getNumberOfCells()),nbNodes(getNumberOfNodes());
11540 MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
11541 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfCells,1);
11542 int *retPt(ret->getPointer());
11543 MCAuto<DataArrayInt> newConn(DataArrayInt::New()); newConn->alloc(0,1);
11544 MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
11545 const int *oldc(_nodal_connec->begin());
11546 const int *oldci(_nodal_connec_index->begin());
11547 const double *coords(_coords->begin());
11548 for(int i=0;i<nbOfCells;i++,oldci++,retPt++)
11550 std::vector<int> a; std::vector<double> b;
11551 INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
11552 std::size_t nbOfTet(a.size()/4); *retPt=(int)nbOfTet;
11553 const int *aa(&a[0]);
11556 for(std::vector<int>::iterator it=a.begin();it!=a.end();it++)
11558 *it=(-(*(it))-1+nbNodes);
11559 addPts->insertAtTheEnd(b.begin(),b.end());
11560 nbNodes+=(int)b.size()/3;
11562 for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
11563 newConn->insertAtTheEnd(aa,aa+4);
11565 if(!addPts->empty())
11567 addPts->rearrange(3);
11568 nbOfAdditionalPoints=addPts->getNumberOfTuples();
11569 addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
11570 ret0->setCoords(addPts);
11574 nbOfAdditionalPoints=0;
11575 ret0->setCoords(getCoords());
11577 ret0->setNodalConnectivity(newConn);
11579 ret->computeOffsetsFull();
11580 n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
11581 return ret0.retn();
11585 * 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).
11587 * \sa MEDCouplingUMesh::split2DCells
11589 void MEDCouplingUMesh::split2DCellsLinear(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI)
11591 checkConnectivityFullyDefined();
11592 int ncells(getNumberOfCells()),lgthToReach(getNodalConnectivityArrayLen()+subNodesInSeg->getNumberOfTuples());
11593 MCAuto<DataArrayInt> c(DataArrayInt::New()); c->alloc((std::size_t)lgthToReach);
11594 const int *subPtr(subNodesInSeg->begin()),*subIPtr(subNodesInSegI->begin()),*descPtr(desc->begin()),*descIPtr(descI->begin()),*oldConn(getNodalConnectivity()->begin());
11595 int *cPtr(c->getPointer()),*ciPtr(getNodalConnectivityIndex()->getPointer());
11596 int prevPosOfCi(ciPtr[0]);
11597 for(int i=0;i<ncells;i++,ciPtr++,descIPtr++)
11599 int offset(descIPtr[0]),sz(descIPtr[1]-descIPtr[0]),deltaSz(0);
11600 *cPtr++=(int)INTERP_KERNEL::NORM_POLYGON; *cPtr++=oldConn[prevPosOfCi+1];
11601 for(int j=0;j<sz;j++)
11603 int offset2(subIPtr[descPtr[offset+j]]),sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]);
11604 for(int k=0;k<sz2;k++)
11605 *cPtr++=subPtr[offset2+k];
11607 *cPtr++=oldConn[prevPosOfCi+j+2];
11610 prevPosOfCi=ciPtr[1];
11611 ciPtr[1]=ciPtr[0]+1+sz+deltaSz;//sz==old nb of nodes because (nb of subedges=nb of nodes for polygons)
11614 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCellsLinear : Some of edges to be split are orphan !");
11615 _nodal_connec->decrRef();
11616 _nodal_connec=c.retn(); _types.clear(); _types.insert(INTERP_KERNEL::NORM_POLYGON);
11619 int InternalAddPoint(const INTERP_KERNEL::Edge *e, int id, const double *coo, int startId, int endId, DataArrayDouble& addCoo, int& nodesCnter)
11625 int ret(nodesCnter++);
11627 e->getMiddleOfPoints(coo+2*startId,coo+2*endId,newPt);
11628 addCoo.insertAtTheEnd(newPt,newPt+2);
11633 int InternalAddPointOriented(const INTERP_KERNEL::Edge *e, int id, const double *coo, int startId, int endId, DataArrayDouble& addCoo, int& nodesCnter)
11639 int ret(nodesCnter++);
11641 e->getMiddleOfPointsOriented(coo+2*startId,coo+2*endId,newPt);
11642 addCoo.insertAtTheEnd(newPt,newPt+2);
11650 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)
11653 int trueStart(start>=0?start:nbOfEdges+start);
11654 tmp[0]=linOrArc?(int)INTERP_KERNEL::NORM_QPOLYG:(int)INTERP_KERNEL::NORM_POLYGON; tmp[1]=connBg[trueStart]; tmp[2]=connBg[stp];
11655 newConnOfCell->insertAtTheEnd(tmp,tmp+3);
11660 int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11661 InternalAddPointOriented(e,-1,coords,tmp[1],tmp[2],*appendedCoords,tmp2);
11662 middles.push_back(tmp3+offset);
11665 middles.push_back(connBg[trueStart+nbOfEdges]);
11669 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)
11671 int tmpSrt(newConnOfCell->back()),tmpEnd(connBg[stp]);
11672 newConnOfCell->pushBackSilent(tmpEnd);
11677 int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11678 InternalAddPointOriented(e,-1,coords,tmpSrt,tmpEnd,*appendedCoords,tmp2);
11679 middles.push_back(tmp3+offset);
11682 middles.push_back(connBg[start+nbOfEdges]);
11686 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)
11688 // only the quadratic point to deal with:
11693 int tmpSrt(connBg[start]),tmpEnd(connBg[stp]);
11694 int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11695 InternalAddPointOriented(e,-1,coords,tmpSrt,tmpEnd,*appendedCoords,tmp2);
11696 middles.push_back(tmp3+offset);
11699 middles.push_back(connBg[start+nbOfEdges]);
11706 * 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 ) .
11707 * \a appendedCoords is a DataArrayDouble instance with number of components equal to one (even if the items are pushed by pair).
11709 bool MEDCouplingUMesh::Colinearize2DCell(const double *coords, const int *connBg, const int *connEnd, int offset, DataArrayInt *newConnOfCell, DataArrayDouble *appendedCoords)
11711 std::size_t sz(std::distance(connBg,connEnd));
11712 if(sz<3)//3 because 2+1(for the cell type) and 2 is the minimal number of edges of 2D cell.
11713 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Colinearize2DCell : the input cell has invalid format !");
11715 INTERP_KERNEL::AutoPtr<int> tmpConn(new int[sz]);
11716 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connBg[0]));
11717 unsigned nbs(cm.getNumberOfSons2(connBg+1,sz));
11718 unsigned nbOfHit(0); // number of fusions operated
11719 int posBaseElt(0),posEndElt(0),nbOfTurn(0);
11720 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
11721 INTERP_KERNEL::NormalizedCellType typeOfSon;
11722 std::vector<int> middles;
11724 for(;(nbOfTurn+nbOfHit)<nbs;nbOfTurn++)
11726 cm.fillSonCellNodalConnectivity2(posBaseElt,connBg+1,sz,tmpConn,typeOfSon);
11727 std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
11728 INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11729 posEndElt = posBaseElt+1;
11731 // Look backward first: are the final edges of the cells colinear with the first ones?
11732 // This initializes posBaseElt.
11735 for(unsigned i=1;i<nbs && nbOfHit<maxNbOfHit;i++) // 2nd condition is to avoid ending with a cell wih one single edge
11737 cm.fillSonCellNodalConnectivity2(nbs-i,connBg+1,sz,tmpConn,typeOfSon);
11738 INTERP_KERNEL::Edge *eCand(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11739 INTERP_KERNEL::EdgeIntersector *eint(INTERP_KERNEL::Edge::BuildIntersectorWith(e,eCand));
11740 bool isColinear=eint->areColinears();
11753 // Now move forward:
11754 const unsigned fwdStart = (nbOfTurn == 0 ? 0 : posBaseElt); // the first element to be inspected going forward
11755 for(unsigned j=fwdStart+1;j<nbs && nbOfHit<maxNbOfHit;j++) // 2nd condition is to avoid ending with a cell wih one single edge
11757 cm.fillSonCellNodalConnectivity2((int)j,connBg+1,sz,tmpConn,typeOfSon); // get edge #j's connectivity
11758 INTERP_KERNEL::Edge *eCand(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11759 INTERP_KERNEL::EdgeIntersector *eint(INTERP_KERNEL::Edge::BuildIntersectorWith(e,eCand));
11760 bool isColinear(eint->areColinears());
11772 //push [posBaseElt,posEndElt) in newConnOfCell using e
11773 // 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!
11775 // at the begining of the connectivity (insert type)
11776 EnterTheResultOf2DCellFirst(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
11777 else if((nbOfHit+nbOfTurn) != (nbs-1))
11779 EnterTheResultOf2DCellMiddle(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
11780 if ((nbOfHit+nbOfTurn) == (nbs-1))
11781 // at the end (only quad points to deal with)
11782 EnterTheResultOf2DCellEnd(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
11783 posBaseElt=posEndElt;
11786 if(!middles.empty())
11787 newConnOfCell->insertAtTheEnd(middles.begin(),middles.end());
11792 * It is the quadratic part of MEDCouplingUMesh::split2DCells. Here some additionnal nodes can be added at the end of coordinates array object.
11794 * \return int - the number of new nodes created.
11795 * \sa MEDCouplingUMesh::split2DCells
11797 int MEDCouplingUMesh::split2DCellsQuadratic(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *mid, const DataArrayInt *midI)
11799 checkConsistencyLight();
11800 int ncells(getNumberOfCells()),lgthToReach(getNodalConnectivityArrayLen()+2*subNodesInSeg->getNumberOfTuples()),nodesCnt(getNumberOfNodes());
11801 MCAuto<DataArrayInt> c(DataArrayInt::New()); c->alloc((std::size_t)lgthToReach);
11802 MCAuto<DataArrayDouble> addCoo(DataArrayDouble::New()); addCoo->alloc(0,1);
11803 const int *subPtr(subNodesInSeg->begin()),*subIPtr(subNodesInSegI->begin()),*descPtr(desc->begin()),*descIPtr(descI->begin()),*oldConn(getNodalConnectivity()->begin());
11804 const int *midPtr(mid->begin()),*midIPtr(midI->begin());
11805 const double *oldCoordsPtr(getCoords()->begin());
11806 int *cPtr(c->getPointer()),*ciPtr(getNodalConnectivityIndex()->getPointer());
11807 int prevPosOfCi(ciPtr[0]);
11808 for(int i=0;i<ncells;i++,ciPtr++,descIPtr++)
11810 int offset(descIPtr[0]),sz(descIPtr[1]-descIPtr[0]),deltaSz(sz);
11811 for(int j=0;j<sz;j++)
11812 { int sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]); deltaSz+=sz2; }
11813 *cPtr++=(int)INTERP_KERNEL::NORM_QPOLYG; cPtr[0]=oldConn[prevPosOfCi+1];
11814 for(int j=0;j<sz;j++)//loop over subedges of oldConn
11816 int offset2(subIPtr[descPtr[offset+j]]),sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]),offset3(midIPtr[descPtr[offset+j]]);
11820 cPtr[1]=oldConn[prevPosOfCi+2+j];
11821 cPtr[deltaSz]=oldConn[prevPosOfCi+1+j+sz]; cPtr++;
11824 std::vector<INTERP_KERNEL::Node *> ns(3);
11825 ns[0]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+j]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+j]+1]);
11826 ns[1]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+(1+j)%sz]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+(1+j)%sz]+1]);
11827 ns[2]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+sz+j]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+sz+j]+1]);
11828 MCAuto<INTERP_KERNEL::Edge> e(INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(ns));
11829 for(int k=0;k<sz2;k++)//loop over subsplit of current subedge
11831 cPtr[1]=subPtr[offset2+k];
11832 cPtr[deltaSz]=InternalAddPoint(e,midPtr[offset3+k],oldCoordsPtr,cPtr[0],cPtr[1],*addCoo,nodesCnt); cPtr++;
11834 int tmpEnd(oldConn[prevPosOfCi+1+(j+1)%sz]);
11836 { cPtr[1]=tmpEnd; }
11837 cPtr[deltaSz]=InternalAddPoint(e,midPtr[offset3+sz2],oldCoordsPtr,cPtr[0],tmpEnd,*addCoo,nodesCnt); cPtr++;
11839 prevPosOfCi=ciPtr[1]; cPtr+=deltaSz;
11840 ciPtr[1]=ciPtr[0]+1+2*deltaSz;//sz==old nb of nodes because (nb of subedges=nb of nodes for polygons)
11843 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCellsQuadratic : Some of edges to be split are orphan !");
11844 _nodal_connec->decrRef();
11845 _nodal_connec=c.retn(); _types.clear(); _types.insert(INTERP_KERNEL::NORM_QPOLYG);
11846 addCoo->rearrange(2);
11847 MCAuto<DataArrayDouble> coo(DataArrayDouble::Aggregate(getCoords(),addCoo));//info are copied from getCoords() by using Aggregate
11849 return addCoo->getNumberOfTuples();
11852 void MEDCouplingUMesh::ComputeAllTypesInternal(std::set<INTERP_KERNEL::NormalizedCellType>& types, const DataArrayInt *nodalConnec, const DataArrayInt *nodalConnecIndex)
11854 if(nodalConnec && nodalConnecIndex)
11857 const int *conn(nodalConnec->getConstPointer()),*connIndex(nodalConnecIndex->getConstPointer());
11858 int nbOfElem(nodalConnecIndex->getNbOfElems()-1);
11860 for(const int *pt=connIndex;pt!=connIndex+nbOfElem;pt++)
11861 types.insert((INTERP_KERNEL::NormalizedCellType)conn[*pt]);
11865 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
11866 _own_cell(true),_cell_id(-1),_nb_cell(0)
11871 _nb_cell=mesh->getNumberOfCells();
11875 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
11883 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_cell(itc),
11884 _own_cell(false),_cell_id(bg-1),
11891 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
11894 if(_cell_id<_nb_cell)
11903 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
11909 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
11911 return new MEDCouplingUMeshCellByTypeIterator(_mesh);
11914 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
11920 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh, INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_type(type),
11928 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
11934 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
11939 int MEDCouplingUMeshCellEntry::getNumberOfElems() const
11944 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
11946 return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
11949 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
11954 _nb_cell=mesh->getNumberOfCells();
11958 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
11965 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
11967 const int *c=_mesh->getNodalConnectivity()->getConstPointer();
11968 const int *ci=_mesh->getNodalConnectivityIndex()->getConstPointer();
11969 if(_cell_id<_nb_cell)
11971 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
11972 int nbOfElems=(int)std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type)));
11973 int startId=_cell_id;
11974 _cell_id+=nbOfElems;
11975 return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
11981 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
11985 _conn=mesh->getNodalConnectivity()->getPointer();
11986 _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
11990 void MEDCouplingUMeshCell::next()
11992 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
11997 _conn_lgth=_conn_indx[1]-_conn_indx[0];
12000 std::string MEDCouplingUMeshCell::repr() const
12002 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
12004 std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
12006 std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<int>(oss," "));
12010 return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
12013 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
12015 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
12016 return (INTERP_KERNEL::NormalizedCellType)_conn[0];
12018 return INTERP_KERNEL::NORM_ERROR;
12021 const int *MEDCouplingUMeshCell::getAllConn(int& lgth) const
12024 if(_conn_lgth!=NOTICABLE_FIRST_VAL)