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().c_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().c_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().c_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().c_str());
271 std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " in connectivity ! sounds bad !";
272 throw INTERP_KERNEL::Exception(oss.str().c_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().c_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().c_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().c_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;
680 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
681 * this->getMeshDimension(), that bound cells of \a this mesh. In addition arrays
682 * describing correspondence between cells of \a this and the result meshes are
683 * returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending connectivity,
684 * i.e. enumerate cells of the result mesh bounding each cell of \a this mesh. The
685 * arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
686 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
687 * \warning For speed reasons, this method does not check if node ids in the nodal
688 * connectivity correspond to the size of node coordinates array.
689 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
690 * to write this mesh to the MED file, its cells must be sorted using
691 * sortCellsInMEDFileFrmt().
692 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
693 * each cell of \a this mesh.
694 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
695 * dividing cell ids in \a desc into groups each referring to one
696 * cell of \a this mesh. Its every element (except the last one) is an index
697 * pointing to the first id of a group of cells. For example cells of the
698 * result mesh bounding the cell #1 of \a this mesh are described by following
700 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
701 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
702 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
703 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
704 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
705 * by each cell of the result mesh.
706 * \param [in,out] revDescIndx - the array, of length one more than number of cells
707 * in the result mesh,
708 * dividing cell ids in \a revDesc into groups each referring to one
709 * cell of the result mesh the same way as \a descIndx divides \a desc.
710 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
711 * delete this mesh using decrRef() as it is no more needed.
712 * \throw If the coordinates array is not set.
713 * \throw If the nodal connectivity of cells is node defined.
714 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
715 * revDescIndx == NULL.
717 * \if ENABLE_EXAMPLES
718 * \ref cpp_mcumesh_buildDescendingConnectivity "Here is a C++ example".<br>
719 * \ref py_mcumesh_buildDescendingConnectivity "Here is a Python example".
721 * \sa buildDescendingConnectivity2()
723 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
725 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
729 * \a this has to have a mesh dimension equal to 3. If it is not the case an INTERP_KERNEL::Exception will be thrown.
730 * This behaves exactly as MEDCouplingUMesh::buildDescendingConnectivity does except that this method compute directly the transition from mesh dimension 3 to sub edges (dimension 1)
731 * in one shot. That is to say that this method is equivalent to 2 successive calls to MEDCouplingUMesh::buildDescendingConnectivity.
732 * This method returns 4 arrays and a mesh as MEDCouplingUMesh::buildDescendingConnectivity does.
733 * \sa MEDCouplingUMesh::buildDescendingConnectivity
735 MEDCouplingUMesh *MEDCouplingUMesh::explode3DMeshTo1D(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
738 if(getMeshDimension()!=3)
739 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explode3DMeshTo1D : This has to have a mesh dimension to 3 !");
740 return buildDescendingConnectivityGen<MinusTwoSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
744 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
745 * this->getMeshDimension(), that bound cells of \a this mesh. In
746 * addition arrays describing correspondence between cells of \a this and the result
747 * meshes are returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending
748 * connectivity, i.e. enumerate cells of the result mesh bounding each cell of \a this
749 * mesh. This method differs from buildDescendingConnectivity() in that apart
750 * from cell ids, \a desc returns mutual orientation of cells in \a this and the
751 * result meshes. So a positive id means that order of nodes in corresponding cells
752 * of two meshes is same, and a negative id means a reverse order of nodes. Since a
753 * cell with id #0 can't be negative, the array \a desc returns ids in FORTRAN mode,
754 * i.e. cell ids are one-based.
755 * Arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
756 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
757 * \warning For speed reasons, this method does not check if node ids in the nodal
758 * connectivity correspond to the size of node coordinates array.
759 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
760 * to write this mesh to the MED file, its cells must be sorted using
761 * sortCellsInMEDFileFrmt().
762 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
763 * each cell of \a this mesh.
764 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
765 * dividing cell ids in \a desc into groups each referring to one
766 * cell of \a this mesh. Its every element (except the last one) is an index
767 * pointing to the first id of a group of cells. For example cells of the
768 * result mesh bounding the cell #1 of \a this mesh are described by following
770 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
771 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
772 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
773 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
774 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
775 * by each cell of the result mesh.
776 * \param [in,out] revDescIndx - the array, of length one more than number of cells
777 * in the result mesh,
778 * dividing cell ids in \a revDesc into groups each referring to one
779 * cell of the result mesh the same way as \a descIndx divides \a desc.
780 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This result mesh
781 * shares the node coordinates array with \a this mesh. The caller is to
782 * delete this mesh using decrRef() as it is no more needed.
783 * \throw If the coordinates array is not set.
784 * \throw If the nodal connectivity of cells is node defined.
785 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
786 * revDescIndx == NULL.
788 * \if ENABLE_EXAMPLES
789 * \ref cpp_mcumesh_buildDescendingConnectivity2 "Here is a C++ example".<br>
790 * \ref py_mcumesh_buildDescendingConnectivity2 "Here is a Python example".
792 * \sa buildDescendingConnectivity()
794 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
796 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingOrientationSensitiveNbrer);
800 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
801 * For speed reasons no check of this will be done. This method calls
802 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
803 * This method lists cell by cell in \b this which are its neighbors. To compute the result
804 * only connectivities are considered.
805 * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
806 * The format of return is hence \ref numbering-indirect.
808 * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly
809 * allocated and should be dealt by the caller. \b neighborsIndx 2nd output
810 * parameter allows to select the right part in this array (\ref numbering-indirect). The number of tuples
811 * is equal to the last values in \b neighborsIndx.
812 * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be
813 * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
815 void MEDCouplingUMesh::computeNeighborsOfCells(DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx) const
817 MCAuto<DataArrayInt> desc=DataArrayInt::New();
818 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
819 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
820 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
821 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
823 ComputeNeighborsOfCellsAdv(desc,descIndx,revDesc,revDescIndx,neighbors,neighborsIndx);
827 * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm
828 * of MEDCouplingUMesh::computeNeighborsOfCells.
829 * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is
830 * typically the case to extract a set a neighbours,
831 * excluding a set of meshdim-1 cells in input descending connectivity.
832 * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx (\ref numbering-indirect) input params are
833 * the result of MEDCouplingUMesh::buildDescendingConnectivity.
834 * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities
836 * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
838 * \param [in] desc descending connectivity array.
839 * \param [in] descIndx descending connectivity index array used to walk through \b desc (\ref numbering-indirect).
840 * \param [in] revDesc reverse descending connectivity array.
841 * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc (\ref numbering-indirect).
842 * \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
843 * parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
844 * \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.
846 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayInt *desc, const DataArrayInt *descIndx, const DataArrayInt *revDesc, const DataArrayInt *revDescIndx,
847 DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx)
849 if(!desc || !descIndx || !revDesc || !revDescIndx)
850 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
851 const int *descPtr=desc->getConstPointer();
852 const int *descIPtr=descIndx->getConstPointer();
853 const int *revDescPtr=revDesc->getConstPointer();
854 const int *revDescIPtr=revDescIndx->getConstPointer();
856 int nbCells=descIndx->getNumberOfTuples()-1;
857 MCAuto<DataArrayInt> out0=DataArrayInt::New();
858 MCAuto<DataArrayInt> out1=DataArrayInt::New(); out1->alloc(nbCells+1,1);
859 int *out1Ptr=out1->getPointer();
861 out0->reserve(desc->getNumberOfTuples());
862 for(int i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
864 for(const int *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
866 std::set<int> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
868 out0->insertAtTheEnd(s.begin(),s.end());
870 *out1Ptr=out0->getNumberOfTuples();
872 neighbors=out0.retn();
873 neighborsIndx=out1.retn();
877 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
878 * For speed reasons no check of this will be done. This method calls
879 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
880 * This method lists node by node in \b this which are its neighbors. To compute the result
881 * only connectivities are considered.
882 * The neighbor nodes of node having id 'nodeId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
884 * \param [out] neighbors is an array storing all the neighbors of all nodes in \b this. This array
885 * is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
886 * parameter allows to select the right part in this array (\ref numbering-indirect).
887 * The number of tuples is equal to the last values in \b neighborsIndx.
888 * \param [out] neighborsIdx is an array of size this->getNumberOfCells()+1 newly allocated and should
889 * be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
891 void MEDCouplingUMesh::computeNeighborsOfNodes(DataArrayInt *&neighbors, DataArrayInt *&neighborsIdx) const
894 int mdim(getMeshDimension()),nbNodes(getNumberOfNodes());
895 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descIndx(DataArrayInt::New()),revDesc(DataArrayInt::New()),revDescIndx(DataArrayInt::New());
896 MCAuto<MEDCouplingUMesh> mesh1D;
901 mesh1D=explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx);
906 mesh1D=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
911 mesh1D=const_cast<MEDCouplingUMesh *>(this);
917 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2,1] !");
920 desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=0; revDescIndx=0;
921 mesh1D->getReverseNodalConnectivity(desc,descIndx);
922 MCAuto<DataArrayInt> ret0(DataArrayInt::New());
923 ret0->alloc(desc->getNumberOfTuples(),1);
924 int *r0Pt(ret0->getPointer());
925 const int *c1DPtr(mesh1D->getNodalConnectivity()->begin()),*rn(desc->begin()),*rni(descIndx->begin());
926 for(int i=0;i<nbNodes;i++,rni++)
928 for(const int *oneDCellIt=rn+rni[0];oneDCellIt!=rn+rni[1];oneDCellIt++)
929 *r0Pt++=c1DPtr[3*(*oneDCellIt)+1]==i?c1DPtr[3*(*oneDCellIt)+2]:c1DPtr[3*(*oneDCellIt)+1];
931 neighbors=ret0.retn();
932 neighborsIdx=descIndx.retn();
938 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
939 * For speed reasons no check of this will be done.
941 template<class SonsGenerator>
942 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivityGen(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx, DimM1DescNbrer nbrer) const
944 if(!desc || !descIndx || !revDesc || !revDescIndx)
945 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildDescendingConnectivityGen : present of a null pointer in input !");
946 checkConnectivityFullyDefined();
947 int nbOfCells=getNumberOfCells();
948 int nbOfNodes=getNumberOfNodes();
949 MCAuto<DataArrayInt> revNodalIndx=DataArrayInt::New(); revNodalIndx->alloc(nbOfNodes+1,1); revNodalIndx->fillWithZero();
950 int *revNodalIndxPtr=revNodalIndx->getPointer();
951 const int *conn=_nodal_connec->getConstPointer();
952 const int *connIndex=_nodal_connec_index->getConstPointer();
953 std::string name="Mesh constituent of "; name+=getName();
954 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(name,getMeshDimension()-SonsGenerator::DELTA);
955 ret->setCoords(getCoords());
956 ret->allocateCells(2*nbOfCells);
957 descIndx->alloc(nbOfCells+1,1);
958 MCAuto<DataArrayInt> revDesc2(DataArrayInt::New()); revDesc2->reserve(2*nbOfCells);
959 int *descIndxPtr=descIndx->getPointer(); *descIndxPtr++=0;
960 for(int eltId=0;eltId<nbOfCells;eltId++,descIndxPtr++)
962 int pos=connIndex[eltId];
963 int posP1=connIndex[eltId+1];
964 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[pos]);
965 SonsGenerator sg(cm);
966 unsigned nbOfSons=sg.getNumberOfSons2(conn+pos+1,posP1-pos-1);
967 INTERP_KERNEL::AutoPtr<int> tmp=new int[posP1-pos];
968 for(unsigned i=0;i<nbOfSons;i++)
970 INTERP_KERNEL::NormalizedCellType cmsId;
971 unsigned nbOfNodesSon=sg.fillSonCellNodalConnectivity2(i,conn+pos+1,posP1-pos-1,tmp,cmsId);
972 for(unsigned k=0;k<nbOfNodesSon;k++)
974 revNodalIndxPtr[tmp[k]+1]++;
975 ret->insertNextCell(cmsId,nbOfNodesSon,tmp);
976 revDesc2->pushBackSilent(eltId);
978 descIndxPtr[0]=descIndxPtr[-1]+(int)nbOfSons;
980 int nbOfCellsM1=ret->getNumberOfCells();
981 std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<int>());
982 MCAuto<DataArrayInt> revNodal=DataArrayInt::New(); revNodal->alloc(revNodalIndx->back(),1);
983 std::fill(revNodal->getPointer(),revNodal->getPointer()+revNodalIndx->back(),-1);
984 int *revNodalPtr=revNodal->getPointer();
985 const int *connM1=ret->getNodalConnectivity()->getConstPointer();
986 const int *connIndexM1=ret->getNodalConnectivityIndex()->getConstPointer();
987 for(int eltId=0;eltId<nbOfCellsM1;eltId++)
989 const int *strtNdlConnOfCurCell=connM1+connIndexM1[eltId]+1;
990 const int *endNdlConnOfCurCell=connM1+connIndexM1[eltId+1];
991 for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
992 if(*iter>=0)//for polyhedrons
993 *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind2nd(std::equal_to<int>(),-1))=eltId;
996 DataArrayInt *commonCells=0,*commonCellsI=0;
997 FindCommonCellsAlg(3,0,ret->getNodalConnectivity(),ret->getNodalConnectivityIndex(),revNodal,revNodalIndx,commonCells,commonCellsI);
998 MCAuto<DataArrayInt> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
999 const int *commonCellsPtr(commonCells->getConstPointer()),*commonCellsIPtr(commonCellsI->getConstPointer());
1000 int newNbOfCellsM1=-1;
1001 MCAuto<DataArrayInt> o2nM1=DataArrayInt::ConvertIndexArrayToO2N(nbOfCellsM1,commonCells->begin(),
1002 commonCellsI->begin(),commonCellsI->end(),newNbOfCellsM1);
1003 std::vector<bool> isImpacted(nbOfCellsM1,false);
1004 for(const int *work=commonCellsI->begin();work!=commonCellsI->end()-1;work++)
1005 for(int work2=work[0];work2!=work[1];work2++)
1006 isImpacted[commonCellsPtr[work2]]=true;
1007 const int *o2nM1Ptr=o2nM1->getConstPointer();
1008 MCAuto<DataArrayInt> n2oM1=o2nM1->invertArrayO2N2N2OBis(newNbOfCellsM1);
1009 const int *n2oM1Ptr=n2oM1->getConstPointer();
1010 MCAuto<MEDCouplingUMesh> ret2=static_cast<MEDCouplingUMesh *>(ret->buildPartOfMySelf(n2oM1->begin(),n2oM1->end(),true));
1011 ret2->copyTinyInfoFrom(this);
1012 desc->alloc(descIndx->back(),1);
1013 int *descPtr=desc->getPointer();
1014 const INTERP_KERNEL::CellModel& cmsDft=INTERP_KERNEL::CellModel::GetCellModel(INTERP_KERNEL::NORM_POINT1);
1015 for(int i=0;i<nbOfCellsM1;i++,descPtr++)
1018 *descPtr=nbrer(o2nM1Ptr[i],0,cmsDft,false,0,0);
1021 if(i!=n2oM1Ptr[o2nM1Ptr[i]])
1023 const INTERP_KERNEL::CellModel& cms=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connM1[connIndexM1[i]]);
1024 *descPtr=nbrer(o2nM1Ptr[i],connIndexM1[i+1]-connIndexM1[i]-1,cms,true,connM1+connIndexM1[n2oM1Ptr[o2nM1Ptr[i]]]+1,connM1+connIndexM1[i]+1);
1027 *descPtr=nbrer(o2nM1Ptr[i],0,cmsDft,false,0,0);
1030 revDesc->reserve(newNbOfCellsM1);
1031 revDescIndx->alloc(newNbOfCellsM1+1,1);
1032 int *revDescIndxPtr=revDescIndx->getPointer(); *revDescIndxPtr++=0;
1033 const int *revDesc2Ptr=revDesc2->getConstPointer();
1034 for(int i=0;i<newNbOfCellsM1;i++,revDescIndxPtr++)
1036 int oldCellIdM1=n2oM1Ptr[i];
1037 if(!isImpacted[oldCellIdM1])
1039 revDesc->pushBackSilent(revDesc2Ptr[oldCellIdM1]);
1040 revDescIndxPtr[0]=revDescIndxPtr[-1]+1;
1044 for(int j=commonCellsIPtr[0];j<commonCellsIPtr[1];j++)
1045 revDesc->pushBackSilent(revDesc2Ptr[commonCellsPtr[j]]);
1046 revDescIndxPtr[0]=revDescIndxPtr[-1]+commonCellsIPtr[1]-commonCellsIPtr[0];
1054 struct MEDCouplingAccVisit
1056 MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1057 int operator()(int val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1058 int _new_nb_of_nodes;
1064 * Converts specified cells to either polygons (if \a this is a 2D mesh) or
1065 * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an
1066 * array of cell ids. Pay attention that after conversion all algorithms work slower
1067 * with \a this mesh than before conversion. <br> If an exception is thrown during the
1068 * conversion due presence of invalid ids in the array of cells to convert, as a
1069 * result \a this mesh contains some already converted elements. In this case the 2D
1070 * mesh remains valid but 3D mesh becomes \b inconsistent!
1071 * \warning This method can significantly modify the order of geometric types in \a this,
1072 * hence, to write this mesh to the MED file, its cells must be sorted using
1073 * sortCellsInMEDFileFrmt().
1074 * \param [in] cellIdsToConvertBg - the array holding ids of cells to convert.
1075 * \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a
1076 * cellIdsToConvertBg.
1077 * \throw If the coordinates array is not set.
1078 * \throw If the nodal connectivity of cells is node defined.
1079 * \throw If dimension of \a this mesh is not either 2 or 3.
1081 * \if ENABLE_EXAMPLES
1082 * \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".<br>
1083 * \ref py_mcumesh_convertToPolyTypes "Here is a Python example".
1086 void MEDCouplingUMesh::convertToPolyTypes(const int *cellIdsToConvertBg, const int *cellIdsToConvertEnd)
1088 checkFullyDefined();
1089 int dim=getMeshDimension();
1091 throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
1092 int nbOfCells(getNumberOfCells());
1095 const int *connIndex=_nodal_connec_index->getConstPointer();
1096 int *conn=_nodal_connec->getPointer();
1097 for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1099 if(*iter>=0 && *iter<nbOfCells)
1101 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
1102 if(!cm.isQuadratic())
1103 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
1105 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
1109 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1110 oss << " in range [0," << nbOfCells << ") !";
1111 throw INTERP_KERNEL::Exception(oss.str().c_str());
1117 int *connIndex(_nodal_connec_index->getPointer());
1118 const int *connOld(_nodal_connec->getConstPointer());
1119 MCAuto<DataArrayInt> connNew(DataArrayInt::New()),connNewI(DataArrayInt::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0);
1120 std::vector<bool> toBeDone(nbOfCells,false);
1121 for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1123 if(*iter>=0 && *iter<nbOfCells)
1124 toBeDone[*iter]=true;
1127 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1128 oss << " in range [0," << nbOfCells << ") !";
1129 throw INTERP_KERNEL::Exception(oss.str().c_str());
1132 for(int cellId=0;cellId<nbOfCells;cellId++)
1134 int pos(connIndex[cellId]),posP1(connIndex[cellId+1]);
1135 int lgthOld(posP1-pos-1);
1136 if(toBeDone[cellId])
1138 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connOld[pos]);
1139 unsigned nbOfFaces(cm.getNumberOfSons2(connOld+pos+1,lgthOld));
1140 int *tmp(new int[nbOfFaces*lgthOld+1]);
1141 int *work=tmp; *work++=INTERP_KERNEL::NORM_POLYHED;
1142 for(unsigned j=0;j<nbOfFaces;j++)
1144 INTERP_KERNEL::NormalizedCellType type;
1145 unsigned offset=cm.fillSonCellNodalConnectivity2(j,connOld+pos+1,lgthOld,work,type);
1149 std::size_t newLgth(std::distance(tmp,work)-1);//-1 for last -1
1150 connNew->pushBackValsSilent(tmp,tmp+newLgth);
1151 connNewI->pushBackSilent(connNewI->back()+(int)newLgth);
1156 connNew->pushBackValsSilent(connOld+pos,connOld+posP1);
1157 connNewI->pushBackSilent(connNewI->back()+posP1-pos);
1160 setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind.
1166 * Converts all cells to either polygons (if \a this is a 2D mesh) or
1167 * polyhedrons (if \a this is a 3D mesh).
1168 * \warning As this method is purely for user-friendliness and no optimization is
1169 * done to avoid construction of a useless vector, this method can be costly
1171 * \throw If the coordinates array is not set.
1172 * \throw If the nodal connectivity of cells is node defined.
1173 * \throw If dimension of \a this mesh is not either 2 or 3.
1175 void MEDCouplingUMesh::convertAllToPoly()
1177 int nbOfCells=getNumberOfCells();
1178 std::vector<int> cellIds(nbOfCells);
1179 for(int i=0;i<nbOfCells;i++)
1181 convertToPolyTypes(&cellIds[0],&cellIds[0]+cellIds.size());
1185 * Fixes nodal connectivity of invalid cells of type NORM_POLYHED. This method
1186 * expects that all NORM_POLYHED cells have connectivity similar to that of prismatic
1187 * volumes like NORM_HEXA8, NORM_PENTA6 etc., i.e. the first half of nodes describes a
1188 * base facet of the volume and the second half of nodes describes an opposite facet
1189 * having the same number of nodes as the base one. This method converts such
1190 * connectivity to a valid polyhedral format where connectivity of each facet is
1191 * explicitly described and connectivity of facets are separated by -1. If \a this mesh
1192 * contains a NORM_POLYHED cell with a valid connectivity, or an invalid connectivity is
1193 * not as expected, an exception is thrown and the mesh remains unchanged. Care of
1194 * a correct orientation of the first facet of a polyhedron, else orientation of a
1195 * corrected cell is reverse.<br>
1196 * This method is useful to build an extruded unstructured mesh with polyhedrons as
1197 * it releases the user from boring description of polyhedra connectivity in the valid
1199 * \throw If \a this->getMeshDimension() != 3.
1200 * \throw If \a this->getSpaceDimension() != 3.
1201 * \throw If the nodal connectivity of cells is not defined.
1202 * \throw If the coordinates array is not set.
1203 * \throw If \a this mesh contains polyhedrons with the valid connectivity.
1204 * \throw If \a this mesh contains polyhedrons with odd number of nodes.
1206 * \if ENABLE_EXAMPLES
1207 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
1208 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
1211 void MEDCouplingUMesh::convertExtrudedPolyhedra()
1213 checkFullyDefined();
1214 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1215 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
1216 int nbOfCells=getNumberOfCells();
1217 MCAuto<DataArrayInt> newCi=DataArrayInt::New();
1218 newCi->alloc(nbOfCells+1,1);
1219 int *newci=newCi->getPointer();
1220 const int *ci=_nodal_connec_index->getConstPointer();
1221 const int *c=_nodal_connec->getConstPointer();
1223 for(int i=0;i<nbOfCells;i++)
1225 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1226 if(type==INTERP_KERNEL::NORM_POLYHED)
1228 if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
1230 std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
1231 throw INTERP_KERNEL::Exception(oss.str().c_str());
1233 std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
1236 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 !";
1237 throw INTERP_KERNEL::Exception(oss.str().c_str());
1240 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)
1243 newci[i+1]=(ci[i+1]-ci[i])+newci[i];
1245 MCAuto<DataArrayInt> newC=DataArrayInt::New();
1246 newC->alloc(newci[nbOfCells],1);
1247 int *newc=newC->getPointer();
1248 for(int i=0;i<nbOfCells;i++)
1250 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1251 if(type==INTERP_KERNEL::NORM_POLYHED)
1253 std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
1254 newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
1256 for(std::size_t j=0;j<n1;j++)
1258 newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
1260 newc[n1+5*j+1]=c[ci[i]+1+j];
1261 newc[n1+5*j+2]=c[ci[i]+1+j+n1];
1262 newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
1263 newc[n1+5*j+4]=c[ci[i]+1+(j+1)%n1];
1268 newc=std::copy(c+ci[i],c+ci[i+1],newc);
1270 _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
1271 _nodal_connec->decrRef(); _nodal_connec=newC.retn();
1276 * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D
1277 * mesh) to cells of classical types. This method is opposite to convertToPolyTypes().
1278 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
1279 * to write this mesh to the MED file, its cells must be sorted using
1280 * sortCellsInMEDFileFrmt().
1281 * \warning Cells (and most notably polyhedrons) must be correctly oriented for this to work
1282 * properly. See orientCorrectlyPolyhedrons() and arePolyhedronsNotCorrectlyOriented().
1283 * \return \c true if at least one cell has been converted, \c false else. In the
1284 * last case the nodal connectivity remains unchanged.
1285 * \throw If the coordinates array is not set.
1286 * \throw If the nodal connectivity of cells is not defined.
1287 * \throw If \a this->getMeshDimension() < 0.
1289 bool MEDCouplingUMesh::unPolyze()
1291 checkFullyDefined();
1292 int mdim=getMeshDimension();
1294 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1297 int nbOfCells=getNumberOfCells();
1300 int initMeshLgth=getNodalConnectivityArrayLen();
1301 int *conn=_nodal_connec->getPointer();
1302 int *index=_nodal_connec_index->getPointer();
1307 for(int i=0;i<nbOfCells;i++)
1309 lgthOfCurCell=index[i+1]-posOfCurCell;
1310 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1311 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1312 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1316 switch(cm.getDimension())
1320 INTERP_KERNEL::AutoPtr<int> tmp=new int[lgthOfCurCell-1];
1321 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(int *)tmp);
1322 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1327 int nbOfFaces,lgthOfPolyhConn;
1328 INTERP_KERNEL::AutoPtr<int> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1329 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1334 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1338 ret=ret || (newType!=type);
1339 conn[newPos]=newType;
1341 posOfCurCell=index[i+1];
1346 std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1347 newPos+=lgthOfCurCell;
1348 posOfCurCell+=lgthOfCurCell;
1352 if(newPos!=initMeshLgth)
1353 _nodal_connec->reAlloc(newPos);
1360 * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1361 * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1362 * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells.
1364 * \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
1367 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1369 checkFullyDefined();
1370 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1371 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1372 MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1373 coords->recenterForMaxPrecision(eps);
1375 int nbOfCells=getNumberOfCells();
1376 const int *conn=_nodal_connec->getConstPointer();
1377 const int *index=_nodal_connec_index->getConstPointer();
1378 MCAuto<DataArrayInt> connINew=DataArrayInt::New();
1379 connINew->alloc(nbOfCells+1,1);
1380 int *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1381 MCAuto<DataArrayInt> connNew=DataArrayInt::New(); connNew->alloc(0,1);
1383 for(int i=0;i<nbOfCells;i++,connINewPtr++)
1385 if(conn[index[i]]==(int)INTERP_KERNEL::NORM_POLYHED)
1387 SimplifyPolyhedronCell(eps,coords,conn+index[i],conn+index[i+1],connNew);
1391 connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1392 *connINewPtr=connNew->getNumberOfTuples();
1395 setConnectivity(connNew,connINew,false);
1399 * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1400 * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1401 * the format of the returned DataArrayInt instance.
1403 * \return a newly allocated DataArrayInt sorted ascendingly of fetched node ids.
1404 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1406 DataArrayInt *MEDCouplingUMesh::computeFetchedNodeIds() const
1408 checkConnectivityFullyDefined();
1409 int nbOfCells=getNumberOfCells();
1410 const int *connIndex=_nodal_connec_index->getConstPointer();
1411 const int *conn=_nodal_connec->getConstPointer();
1412 const int *maxEltPt=std::max_element(_nodal_connec->begin(),_nodal_connec->end());
1413 int maxElt=maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1;
1414 std::vector<bool> retS(maxElt,false);
1415 for(int i=0;i<nbOfCells;i++)
1416 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1420 for(int i=0;i<maxElt;i++)
1423 DataArrayInt *ret=DataArrayInt::New();
1425 int *retPtr=ret->getPointer();
1426 for(int i=0;i<maxElt;i++)
1433 * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1434 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1436 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1438 int nbOfNodes((int)nodeIdsInUse.size()),nbOfCells(getNumberOfCells());
1439 const int *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1440 for(int i=0;i<nbOfCells;i++)
1441 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1444 if(conn[j]<nbOfNodes)
1445 nodeIdsInUse[conn[j]]=true;
1448 std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1449 throw INTERP_KERNEL::Exception(oss.str().c_str());
1455 * Finds nodes not used in any cell and returns an array giving a new id to every node
1456 * by excluding the unused nodes, for which the array holds -1. The result array is
1457 * a mapping in "Old to New" mode.
1458 * \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1459 * \return DataArrayInt * - a new instance of DataArrayInt. Its length is \a
1460 * this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1461 * if the node is unused or a new id else. The caller is to delete this
1462 * array using decrRef() as it is no more needed.
1463 * \throw If the coordinates array is not set.
1464 * \throw If the nodal connectivity of cells is not defined.
1465 * \throw If the nodal connectivity includes an invalid id.
1467 * \if ENABLE_EXAMPLES
1468 * \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1469 * \ref py_mcumesh_getNodeIdsInUse "Here is a Python example".
1471 * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1473 DataArrayInt *MEDCouplingUMesh::getNodeIdsInUse(int& nbrOfNodesInUse) const
1476 int nbOfNodes(getNumberOfNodes());
1477 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1478 ret->alloc(nbOfNodes,1);
1479 int *traducer=ret->getPointer();
1480 std::fill(traducer,traducer+nbOfNodes,-1);
1481 int nbOfCells=getNumberOfCells();
1482 const int *connIndex=_nodal_connec_index->getConstPointer();
1483 const int *conn=_nodal_connec->getConstPointer();
1484 for(int i=0;i<nbOfCells;i++)
1485 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1488 if(conn[j]<nbOfNodes)
1489 traducer[conn[j]]=1;
1492 std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1493 throw INTERP_KERNEL::Exception(oss.str().c_str());
1496 nbrOfNodesInUse=(int)std::count(traducer,traducer+nbOfNodes,1);
1497 std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1502 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1503 * For each cell in \b this the number of nodes constituting cell is computed.
1504 * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1505 * So for pohyhedrons some nodes can be counted several times in the returned result.
1507 * \return a newly allocated array
1508 * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1510 DataArrayInt *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1512 checkConnectivityFullyDefined();
1513 int nbOfCells=getNumberOfCells();
1514 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1515 ret->alloc(nbOfCells,1);
1516 int *retPtr=ret->getPointer();
1517 const int *conn=getNodalConnectivity()->getConstPointer();
1518 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1519 for(int i=0;i<nbOfCells;i++,retPtr++)
1521 if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1522 *retPtr=connI[i+1]-connI[i]-1;
1524 *retPtr=connI[i+1]-connI[i]-1-std::count(conn+connI[i]+1,conn+connI[i+1],-1);
1530 * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1531 * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1533 * \return DataArrayInt * - new object to be deallocated by the caller.
1534 * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1536 DataArrayInt *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() 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 std::set<int> s(conn+connI[i]+1,conn+connI[i+1]);
1548 if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1549 *retPtr=(int)s.size();
1553 *retPtr=(int)s.size();
1560 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1561 * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1563 * \return a newly allocated array
1565 DataArrayInt *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1567 checkConnectivityFullyDefined();
1568 int nbOfCells=getNumberOfCells();
1569 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1570 ret->alloc(nbOfCells,1);
1571 int *retPtr=ret->getPointer();
1572 const int *conn=getNodalConnectivity()->getConstPointer();
1573 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1574 for(int i=0;i<nbOfCells;i++,retPtr++,connI++)
1576 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1577 *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1583 * Removes unused nodes (the node coordinates array is shorten) and returns an array
1584 * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1585 * array mean that the corresponding old node is no more used.
1586 * \return DataArrayInt * - a new instance of DataArrayInt of length \a
1587 * this->getNumberOfNodes() before call of this method. The caller is to
1588 * delete this array using decrRef() as it is no more needed.
1589 * \throw If the coordinates array is not set.
1590 * \throw If the nodal connectivity of cells is not defined.
1591 * \throw If the nodal connectivity includes an invalid id.
1592 * \sa areAllNodesFetched
1594 * \if ENABLE_EXAMPLES
1595 * \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1596 * \ref py_mcumesh_zipCoordsTraducer "Here is a Python example".
1599 DataArrayInt *MEDCouplingUMesh::zipCoordsTraducer()
1601 return MEDCouplingPointSet::zipCoordsTraducer();
1605 * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1606 * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1608 int MEDCouplingUMesh::AreCellsEqual(const int *conn, const int *connI, int cell1, int cell2, int compType)
1613 return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1615 return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1617 return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1619 return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1621 return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1623 throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1627 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1629 int MEDCouplingUMesh::AreCellsEqualPolicy0(const int *conn, const int *connI, int cell1, int cell2)
1631 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1632 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1637 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1639 int MEDCouplingUMesh::AreCellsEqualPolicy1(const int *conn, const int *connI, int cell1, int cell2)
1641 int sz=connI[cell1+1]-connI[cell1];
1642 if(sz==connI[cell2+1]-connI[cell2])
1644 if(conn[connI[cell1]]==conn[connI[cell2]])
1646 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1647 unsigned dim=cm.getDimension();
1653 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1654 int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1655 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1656 work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1657 return work!=tmp+sz1?1:0;
1660 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1663 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1670 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1672 int MEDCouplingUMesh::AreCellsEqualPolicy2(const int *conn, const int *connI, int cell1, int cell2)
1674 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1676 if(conn[connI[cell1]]==conn[connI[cell2]])
1678 std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1679 std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1687 * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1689 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const int *conn, const int *connI, int cell1, int cell2)
1691 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1693 std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1694 std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1701 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1703 int MEDCouplingUMesh::AreCellsEqualPolicy7(const int *conn, const int *connI, int cell1, int cell2)
1705 int sz=connI[cell1+1]-connI[cell1];
1706 if(sz==connI[cell2+1]-connI[cell2])
1708 if(conn[connI[cell1]]==conn[connI[cell2]])
1710 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1711 unsigned dim=cm.getDimension();
1717 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1718 int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1719 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1720 work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1725 std::reverse_iterator<int *> it1((int *)tmp+sz1);
1726 std::reverse_iterator<int *> it2((int *)tmp);
1727 if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1733 return work!=tmp+sz1?1:0;
1736 {//case of SEG2 and SEG3
1737 if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1739 if(!cm.isQuadratic())
1741 std::reverse_iterator<const int *> it1(conn+connI[cell1+1]);
1742 std::reverse_iterator<const int *> it2(conn+connI[cell1]+1);
1743 if(std::equal(it1,it2,conn+connI[cell2]+1))
1749 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])
1756 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1763 * This method find in candidate pool defined by 'candidates' the cells equal following the polycy 'compType'.
1764 * If any true is returned and the results will be put at the end of 'result' output parameter. If not false is returned
1765 * and result remains unchanged.
1766 * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1767 * If in 'candidates' pool -1 value is considered as an empty value.
1768 * WARNING this method returns only ONE set of result !
1770 bool MEDCouplingUMesh::AreCellsEqualInPool(const std::vector<int>& candidates, int compType, const int *conn, const int *connI, DataArrayInt *result)
1772 if(candidates.size()<1)
1775 std::vector<int>::const_iterator iter=candidates.begin();
1776 int start=(*iter++);
1777 for(;iter!=candidates.end();iter++)
1779 int status=AreCellsEqual(conn,connI,start,*iter,compType);
1784 result->pushBackSilent(start);
1788 result->pushBackSilent(*iter);
1790 result->pushBackSilent(status==2?(*iter+1):-(*iter+1));
1797 * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified
1799 * This method keeps the coordiantes of \a this. This method is time consuming.
1801 * \param [in] compType input specifying the technique used to compare cells each other.
1802 * - 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.
1803 * - 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)
1804 * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1805 * - 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
1806 * can be used for users not sensitive to orientation of cell
1807 * \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.
1808 * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1809 * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1810 * \return the correspondance array old to new in a newly allocated array.
1813 void MEDCouplingUMesh::findCommonCells(int compType, int startCellId, DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr) const
1815 MCAuto<DataArrayInt> revNodal=DataArrayInt::New(),revNodalI=DataArrayInt::New();
1816 getReverseNodalConnectivity(revNodal,revNodalI);
1817 FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1820 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, int startCellId, const DataArrayInt *nodal, const DataArrayInt *nodalI, const DataArrayInt *revNodal, const DataArrayInt *revNodalI,
1821 DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr)
1823 MCAuto<DataArrayInt> commonCells=DataArrayInt::New(),commonCellsI=DataArrayInt::New(); commonCells->alloc(0,1);
1824 int nbOfCells=nodalI->getNumberOfTuples()-1;
1825 commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1826 const int *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1827 const int *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1828 std::vector<bool> isFetched(nbOfCells,false);
1831 for(int i=0;i<nbOfCells;i++)
1835 const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1836 std::vector<int> v,v2;
1837 if(connOfNode!=connPtr+connIPtr[i+1])
1839 const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1840 v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1843 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1847 const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1848 std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1849 v2.resize(std::distance(v2.begin(),it));
1853 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1855 int pos=commonCellsI->back();
1856 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1857 for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1858 isFetched[*it]=true;
1866 for(int i=startCellId;i<nbOfCells;i++)
1870 const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1871 std::vector<int> v,v2;
1872 if(connOfNode!=connPtr+connIPtr[i+1])
1874 v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1877 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1881 std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1882 v2.resize(std::distance(v2.begin(),it));
1886 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1888 int pos=commonCellsI->back();
1889 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1890 for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1891 isFetched[*it]=true;
1897 commonCellsArr=commonCells.retn();
1898 commonCellsIArr=commonCellsI.retn();
1902 * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1903 * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1904 * than \a this->getNumberOfCells() in the returned array means that there is no
1905 * corresponding cell in \a this mesh.
1906 * It is expected that \a this and \a other meshes share the same node coordinates
1907 * array, if it is not so an exception is thrown.
1908 * \param [in] other - the mesh to compare with.
1909 * \param [in] compType - specifies a cell comparison technique. For meaning of its
1910 * valid values [0,1,2], see zipConnectivityTraducer().
1911 * \param [out] arr - a new instance of DataArrayInt returning correspondence
1912 * between cells of the two meshes. It contains \a other->getNumberOfCells()
1913 * values. The caller is to delete this array using
1914 * decrRef() as it is no more needed.
1915 * \return bool - \c true if all cells of \a other mesh are present in the \a this
1918 * \if ENABLE_EXAMPLES
1919 * \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1920 * \ref py_mcumesh_areCellsIncludedIn "Here is a Python example".
1922 * \sa checkDeepEquivalOnSameNodesWith()
1923 * \sa checkGeoEquivalWith()
1925 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayInt *& arr) const
1927 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1928 int nbOfCells=getNumberOfCells();
1929 static const int possibleCompType[]={0,1,2};
1930 if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1932 std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1933 std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1935 throw INTERP_KERNEL::Exception(oss.str().c_str());
1937 MCAuto<DataArrayInt> o2n=mesh->zipConnectivityTraducer(compType,nbOfCells);
1938 arr=o2n->subArray(nbOfCells);
1939 arr->setName(other->getName());
1941 if(other->getNumberOfCells()==0)
1943 return arr->getMaxValue(tmp)<nbOfCells;
1947 * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1948 * This method tries to determine if \b other is fully included in \b this.
1949 * The main difference is that this method is not expected to throw exception.
1950 * This method has two outputs :
1952 * \param other other mesh
1953 * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1954 * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
1956 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayInt *& arr) const
1958 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1959 DataArrayInt *commonCells=0,*commonCellsI=0;
1960 int thisNbCells=getNumberOfCells();
1961 mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
1962 MCAuto<DataArrayInt> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1963 const int *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
1964 int otherNbCells=other->getNumberOfCells();
1965 MCAuto<DataArrayInt> arr2=DataArrayInt::New();
1966 arr2->alloc(otherNbCells,1);
1967 arr2->fillWithZero();
1968 int *arr2Ptr=arr2->getPointer();
1969 int nbOfCommon=commonCellsI->getNumberOfTuples()-1;
1970 for(int i=0;i<nbOfCommon;i++)
1972 int start=commonCellsPtr[commonCellsIPtr[i]];
1973 if(start<thisNbCells)
1975 for(int j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
1977 int sig=commonCellsPtr[j]>0?1:-1;
1978 int val=std::abs(commonCellsPtr[j])-1;
1979 if(val>=thisNbCells)
1980 arr2Ptr[val-thisNbCells]=sig*(start+1);
1984 arr2->setName(other->getName());
1985 if(arr2->presenceOfValue(0))
1991 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
1994 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
1995 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
1997 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
1998 std::vector<const MEDCouplingUMesh *> ms(2);
2001 return MergeUMeshesOnSameCoords(ms);
2005 * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
2006 * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
2007 * cellIds is not given explicitely but by a range python like.
2012 * \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.
2013 * \return a newly allocated
2015 * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
2016 * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
2018 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(int start, int end, int step, bool keepCoords) const
2020 if(getMeshDimension()!=-1)
2021 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
2024 int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
2026 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2028 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2030 return const_cast<MEDCouplingUMesh *>(this);
2035 * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
2036 * The result mesh shares or not the node coordinates array with \a this mesh depending
2037 * on \a keepCoords parameter.
2038 * \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
2039 * to write this mesh to the MED file, its cells must be sorted using
2040 * sortCellsInMEDFileFrmt().
2041 * \param [in] begin - an array of cell ids to include to the new mesh.
2042 * \param [in] end - a pointer to last-plus-one-th element of \a begin.
2043 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2044 * array of \a this mesh, else "free" nodes are removed from the result mesh
2045 * by calling zipCoords().
2046 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2047 * to delete this mesh using decrRef() as it is no more needed.
2048 * \throw If the coordinates array is not set.
2049 * \throw If the nodal connectivity of cells is not defined.
2050 * \throw If any cell id in the array \a begin is not valid.
2052 * \if ENABLE_EXAMPLES
2053 * \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
2054 * \ref py_mcumesh_buildPartOfMySelf "Here is a Python example".
2057 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const int *begin, const int *end, bool keepCoords) const
2059 if(getMeshDimension()!=-1)
2060 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
2064 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2066 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2068 return const_cast<MEDCouplingUMesh *>(this);
2073 * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
2075 * 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.
2076 * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
2077 * The number of cells of \b this will remain the same with this method.
2079 * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
2080 * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
2081 * \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 ).
2082 * Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
2084 void MEDCouplingUMesh::setPartOfMySelf(const int *cellIdsBg, const int *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2086 checkConnectivityFullyDefined();
2087 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2088 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2089 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2090 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2092 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2093 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2094 throw INTERP_KERNEL::Exception(oss.str().c_str());
2096 int nbOfCellsToModify=(int)std::distance(cellIdsBg,cellIdsEnd);
2097 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2099 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2100 throw INTERP_KERNEL::Exception(oss.str().c_str());
2102 int nbOfCells=getNumberOfCells();
2103 bool easyAssign=true;
2104 const int *connI=_nodal_connec_index->getConstPointer();
2105 const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2106 for(const int *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2108 if(*it>=0 && *it<nbOfCells)
2110 easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2114 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2115 throw INTERP_KERNEL::Exception(oss.str().c_str());
2120 MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2125 DataArrayInt *arrOut=0,*arrIOut=0;
2126 MEDCouplingUMesh::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2128 MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2129 setConnectivity(arrOut,arrIOut,true);
2133 void MEDCouplingUMesh::setPartOfMySelfSlice(int start, int end, int step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2135 checkConnectivityFullyDefined();
2136 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2137 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2138 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2139 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2141 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2142 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2143 throw INTERP_KERNEL::Exception(oss.str().c_str());
2145 int nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2146 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2148 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2149 throw INTERP_KERNEL::Exception(oss.str().c_str());
2151 int nbOfCells=getNumberOfCells();
2152 bool easyAssign=true;
2153 const int *connI=_nodal_connec_index->getConstPointer();
2154 const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2156 for(int i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2158 if(it>=0 && it<nbOfCells)
2160 easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2164 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2165 throw INTERP_KERNEL::Exception(oss.str().c_str());
2170 MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2175 DataArrayInt *arrOut=0,*arrIOut=0;
2176 MEDCouplingUMesh::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2178 MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2179 setConnectivity(arrOut,arrIOut,true);
2184 * Keeps from \a this only cells which constituing point id are in the ids specified by [ \a begin,\a end ).
2185 * The resulting cell ids are stored at the end of the 'cellIdsKept' parameter.
2186 * Parameter \a fullyIn specifies if a cell that has part of its nodes in ids array is kept or not.
2187 * If \a fullyIn is true only cells whose ids are \b fully contained in [ \a begin,\a end ) tab will be kept.
2189 * \param [in] begin input start of array of node ids.
2190 * \param [in] end input end of array of node ids.
2191 * \param [in] fullyIn input that specifies if all node ids must be in [ \a begin,\a end ) array to consider cell to be in.
2192 * \param [in,out] cellIdsKeptArr array where all candidate cell ids are put at the end.
2194 void MEDCouplingUMesh::fillCellIdsToKeepFromNodeIds(const int *begin, const int *end, bool fullyIn, DataArrayInt *&cellIdsKeptArr) const
2196 MCAuto<DataArrayInt> cellIdsKept=DataArrayInt::New(); cellIdsKept->alloc(0,1);
2197 checkConnectivityFullyDefined();
2199 int sz=getNodalConnectivity()->getMaxValue(tmp); sz=std::max(sz,0)+1;
2200 std::vector<bool> fastFinder(sz,false);
2201 for(const int *work=begin;work!=end;work++)
2202 if(*work>=0 && *work<sz)
2203 fastFinder[*work]=true;
2204 int nbOfCells=getNumberOfCells();
2205 const int *conn=getNodalConnectivity()->getConstPointer();
2206 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2207 for(int i=0;i<nbOfCells;i++)
2209 int ref=0,nbOfHit=0;
2210 for(const int *work2=conn+connIndex[i]+1;work2!=conn+connIndex[i+1];work2++)
2214 if(fastFinder[*work2])
2217 if((ref==nbOfHit && fullyIn) || (nbOfHit!=0 && !fullyIn))
2218 cellIdsKept->pushBackSilent(i);
2220 cellIdsKeptArr=cellIdsKept.retn();
2224 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2225 * this->getMeshDimension(), that bound some cells of \a this mesh.
2226 * The cells of lower dimension to include to the result mesh are selected basing on
2227 * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2228 * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2229 * ==\c false, a cell is copied if any its node is in the array of node ids. The
2230 * created mesh shares the node coordinates array with \a this mesh.
2231 * \param [in] begin - the array of node ids.
2232 * \param [in] end - a pointer to the (last+1)-th element of \a begin.
2233 * \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2234 * array \a begin are added, else cells whose any node is in the
2235 * array \a begin are added.
2236 * \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2237 * to delete this mesh using decrRef() as it is no more needed.
2238 * \throw If the coordinates array is not set.
2239 * \throw If the nodal connectivity of cells is not defined.
2240 * \throw If any node id in \a begin is not valid.
2242 * \if ENABLE_EXAMPLES
2243 * \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2244 * \ref py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2247 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const int *begin, const int *end, bool fullyIn) const
2249 MCAuto<DataArrayInt> desc,descIndx,revDesc,revDescIndx;
2250 desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=DataArrayInt::New(); revDescIndx=DataArrayInt::New();
2251 MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2252 desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2253 return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2257 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2258 * this->getMeshDimension(), which bound only one cell of \a this mesh.
2259 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2260 * array of \a this mesh, else "free" nodes are removed from the result mesh
2261 * by calling zipCoords().
2262 * \return MEDCouplingUMesh * - a 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.
2267 * \if ENABLE_EXAMPLES
2268 * \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2269 * \ref py_mcumesh_buildBoundaryMesh "Here is a Python example".
2272 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2274 DataArrayInt *desc=DataArrayInt::New();
2275 DataArrayInt *descIndx=DataArrayInt::New();
2276 DataArrayInt *revDesc=DataArrayInt::New();
2277 DataArrayInt *revDescIndx=DataArrayInt::New();
2279 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2282 descIndx->decrRef();
2283 int nbOfCells=meshDM1->getNumberOfCells();
2284 const int *revDescIndxC=revDescIndx->getConstPointer();
2285 std::vector<int> boundaryCells;
2286 for(int i=0;i<nbOfCells;i++)
2287 if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2288 boundaryCells.push_back(i);
2289 revDescIndx->decrRef();
2290 MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2295 * This method returns a newly created DataArrayInt instance containing ids of cells located in boundary.
2296 * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2297 * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2299 DataArrayInt *MEDCouplingUMesh::findCellIdsOnBoundary() const
2301 checkFullyDefined();
2302 MCAuto<DataArrayInt> desc=DataArrayInt::New();
2303 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2304 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2305 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2307 buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2308 desc=(DataArrayInt*)0; descIndx=(DataArrayInt*)0;
2310 MCAuto<DataArrayInt> tmp=revDescIndx->deltaShiftIndex();
2311 MCAuto<DataArrayInt> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayInt*)0;
2312 const int *revDescPtr=revDesc->getConstPointer();
2313 const int *revDescIndxPtr=revDescIndx->getConstPointer();
2314 int nbOfCells=getNumberOfCells();
2315 std::vector<bool> ret1(nbOfCells,false);
2317 for(const int *pt=faceIds->begin();pt!=faceIds->end();pt++)
2318 if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2319 { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2321 DataArrayInt *ret2=DataArrayInt::New();
2323 int *ret2Ptr=ret2->getPointer();
2325 for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2328 ret2->setName("BoundaryCells");
2333 * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2334 * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2335 * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2336 * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2338 * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2339 * 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
2340 * equals a cell in \b otherDimM1OnSameCoords.
2342 * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2343 * are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2345 * \param [in] otherDimM1OnSameCoords
2346 * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2347 * \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
2348 * cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2350 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *&cellIdsRk0, DataArrayInt *&cellIdsRk1) const
2352 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2353 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2354 checkConnectivityFullyDefined();
2355 otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2356 if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2357 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2358 MCAuto<DataArrayInt> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2359 MCAuto<DataArrayInt> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2360 MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2361 MCAuto<DataArrayInt> descThisPart=DataArrayInt::New(),descIThisPart=DataArrayInt::New(),revDescThisPart=DataArrayInt::New(),revDescIThisPart=DataArrayInt::New();
2362 MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2363 const int *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2364 DataArrayInt *idsOtherInConsti=0;
2365 bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2366 MCAuto<DataArrayInt> idsOtherInConstiAuto(idsOtherInConsti);
2368 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2370 for(const int *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2371 s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2372 MCAuto<DataArrayInt> s1arr_renum1=DataArrayInt::New(); s1arr_renum1->alloc((int)s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2373 s1arr_renum1->sort();
2374 cellIdsRk0=s0arr.retn();
2375 //cellIdsRk1=s_renum1.retn();
2376 cellIdsRk1=s1arr_renum1.retn();
2380 * 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
2381 * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2383 * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2385 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2387 MCAuto<DataArrayInt> desc=DataArrayInt::New();
2388 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2389 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2390 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2392 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2393 revDesc=0; desc=0; descIndx=0;
2394 MCAuto<DataArrayInt> revDescIndx2=revDescIndx->deltaShiftIndex();
2395 MCAuto<DataArrayInt> part=revDescIndx2->findIdsEqual(1);
2396 return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2400 * Finds nodes lying on the boundary of \a this mesh.
2401 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of found
2402 * nodes. The caller is to delete this array using decrRef() as it is no
2404 * \throw If the coordinates array is not set.
2405 * \throw If the nodal connectivity of cells is node defined.
2407 * \if ENABLE_EXAMPLES
2408 * \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2409 * \ref py_mcumesh_findBoundaryNodes "Here is a Python example".
2412 DataArrayInt *MEDCouplingUMesh::findBoundaryNodes() const
2414 MCAuto<MEDCouplingUMesh> skin=computeSkin();
2415 return skin->computeFetchedNodeIds();
2418 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2421 return const_cast<MEDCouplingUMesh *>(this);
2425 * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2426 * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2427 * 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.
2428 * 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.
2429 * 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.
2431 * \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
2432 * parameter is altered during the call.
2433 * \param [out] nodeIdsToDuplicate node ids needed to be duplicated following the algorithm explain above.
2434 * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2435 * \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.
2437 * \warning This method modifies param \b otherDimM1OnSameCoords (for speed reasons).
2439 void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *& nodeIdsToDuplicate,
2440 DataArrayInt *& cellIdsNeededToBeRenum, DataArrayInt *& cellIdsNotModified) const
2442 typedef MCAuto<DataArrayInt> DAInt;
2443 typedef MCAuto<MEDCouplingUMesh> MCUMesh;
2445 checkFullyDefined();
2446 otherDimM1OnSameCoords.checkFullyDefined();
2447 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2448 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2449 if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2450 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2452 // Checking star-shaped M1 group:
2453 DAInt dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2454 MCUMesh meshM2 = otherDimM1OnSameCoords.buildDescendingConnectivity(dt0, dit0, rdt0, rdit0);
2455 DAInt dsi = rdit0->deltaShiftIndex();
2456 DAInt idsTmp0 = dsi->findIdsNotInRange(-1, 3);
2457 if(idsTmp0->getNumberOfTuples())
2458 throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2459 dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2461 // Get extreme nodes from the group (they won't be duplicated), ie nodes belonging to boundary cells of M1
2462 DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2463 MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2464 DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2465 // Remove from the list points on the boundary of the M0 mesh (those need duplication!)
2466 dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2467 MCUMesh m0desc = buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0;
2468 dsi = rdit0->deltaShiftIndex();
2469 DAInt boundSegs = dsi->findIdsEqual(1); // boundary segs/faces of the M0 mesh
2470 MCUMesh m0descSkin = static_cast<MEDCouplingUMesh *>(m0desc->buildPartOfMySelf(boundSegs->begin(),boundSegs->end(), true));
2471 DAInt fNodes = m0descSkin->computeFetchedNodeIds();
2472 // In 3D, some points on the boundary of M0 still need duplication:
2474 if (getMeshDimension() == 3)
2476 DAInt dnu1=DataArrayInt::New(), dnu2=DataArrayInt::New(), dnu3=DataArrayInt::New(), dnu4=DataArrayInt::New();
2477 MCUMesh m0descSkinDesc = m0descSkin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4);
2478 dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2479 DataArrayInt * corresp=0;
2480 meshM2->areCellsIncludedIn(m0descSkinDesc,2,corresp);
2481 DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2483 if (validIds->getNumberOfTuples())
2485 MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0descSkinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2486 DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2487 DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2488 notDup = xtrem->buildSubstraction(fNodes1);
2491 notDup = xtrem->buildSubstraction(fNodes);
2494 notDup = xtrem->buildSubstraction(fNodes);
2496 // Now compute cells around group (i.e. cells where we will do the propagation to identify the two sub-sets delimited by the group)
2497 DAInt m1Nodes = otherDimM1OnSameCoords.computeFetchedNodeIds();
2498 DAInt dupl = m1Nodes->buildSubstraction(notDup);
2499 DAInt cellsAroundGroup = getCellIdsLyingOnNodes(dupl->begin(), dupl->end(), false); // false= take cell in, even if not all nodes are in notDup
2502 MCUMesh m0Part2=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroup->begin(),cellsAroundGroup->end(),true));
2503 int nCells2 = m0Part2->getNumberOfCells();
2504 DAInt desc00=DataArrayInt::New(),descI00=DataArrayInt::New(),revDesc00=DataArrayInt::New(),revDescI00=DataArrayInt::New();
2505 MCUMesh m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00);
2507 // Neighbor information of the mesh without considering the crack (serves to count how many connex pieces it is made of)
2508 DataArrayInt *tmp00=0,*tmp11=0;
2509 MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00, tmp00, tmp11);
2510 DAInt neighInit00(tmp00);
2511 DAInt neighIInit00(tmp11);
2512 // Neighbor information of the mesh WITH the crack (some neighbors are removed):
2513 DataArrayInt *idsTmp=0;
2514 bool b=m01->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsTmp);
2516 // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2517 // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2518 MEDCouplingUMesh::RemoveIdsFromIndexedArrays(ids->begin(),ids->end(),desc00,descI00);
2519 DataArrayInt *tmp0=0,*tmp1=0;
2520 // Compute the neighbor of each cell in m0Part2, taking into account the broken link above. Two
2521 // cells on either side of the crack (defined by the mesh of low dimension) are not neighbor anymore.
2522 ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00,tmp0,tmp1);
2523 DAInt neigh00(tmp0);
2524 DAInt neighI00(tmp1);
2526 // For each initial connex part of the sub-mesh (or said differently for each independent crack):
2527 int seed = 0, nIter = 0;
2528 int nIterMax = nCells2+1; // Safety net for the loop
2529 DAInt hitCells = DataArrayInt::New(); hitCells->alloc(nCells2);
2530 hitCells->fillWithValue(-1);
2531 DAInt cellsToModifyConn0_torenum = DataArrayInt::New();
2532 cellsToModifyConn0_torenum->alloc(0,1);
2533 while (nIter < nIterMax)
2535 DAInt t = hitCells->findIdsEqual(-1);
2536 if (!t->getNumberOfTuples())
2538 // Connex zone without the crack (to compute the next seed really)
2540 DAInt connexCheck = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neighInit00,neighIInit00, -1, dnu);
2542 for (int * ptr = connexCheck->getPointer(); cnt < connexCheck->getNumberOfTuples(); ptr++, cnt++)
2543 hitCells->setIJ(*ptr,0,1);
2544 // Connex zone WITH the crack (to identify cells lying on either part of the crack)
2545 DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neigh00,neighI00, -1, dnu);
2546 cellsToModifyConn0_torenum = DataArrayInt::Aggregate(cellsToModifyConn0_torenum, spreadZone, 0);
2547 // Compute next seed, i.e. a cell in another connex part, which was not covered by the previous iterations
2548 DAInt comple = cellsToModifyConn0_torenum->buildComplement(nCells2);
2549 DAInt nonHitCells = hitCells->findIdsEqual(-1);
2550 DAInt intersec = nonHitCells->buildIntersection(comple);
2551 if (intersec->getNumberOfTuples())
2552 { seed = intersec->getIJ(0,0); }
2557 if (nIter >= nIterMax)
2558 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate(): internal error - too many iterations.");
2560 DAInt cellsToModifyConn1_torenum=cellsToModifyConn0_torenum->buildComplement(neighI00->getNumberOfTuples()-1);
2561 cellsToModifyConn0_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2562 cellsToModifyConn1_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2564 cellIdsNeededToBeRenum=cellsToModifyConn0_torenum.retn();
2565 cellIdsNotModified=cellsToModifyConn1_torenum.retn();
2566 nodeIdsToDuplicate=dupl.retn();
2570 * This method operates a modification of the connectivity and coords in \b this.
2571 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2572 * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2573 * 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
2574 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2575 * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2577 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2579 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2580 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2582 void MEDCouplingUMesh::duplicateNodes(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd)
2584 int nbOfNodes=getNumberOfNodes();
2585 duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2586 duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2590 * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2591 * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2593 * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2595 * \sa renumberNodesInConn
2597 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(int offset)
2599 checkConnectivityFullyDefined();
2600 int *conn(getNodalConnectivity()->getPointer());
2601 const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2602 int nbOfCells(getNumberOfCells());
2603 for(int i=0;i<nbOfCells;i++)
2604 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2606 int& node=conn[iconn];
2607 if(node>=0)//avoid polyhedron separator
2612 _nodal_connec->declareAsNew();
2617 * Same than renumberNodesInConn(const int *) except that here the format of old-to-new traducer is using map instead
2618 * 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
2621 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<int,int>& newNodeNumbersO2N)
2623 checkConnectivityFullyDefined();
2624 int *conn(getNodalConnectivity()->getPointer());
2625 const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2626 int nbOfCells(getNumberOfCells());
2627 for(int i=0;i<nbOfCells;i++)
2628 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2630 int& node=conn[iconn];
2631 if(node>=0)//avoid polyhedron separator
2633 INTERP_KERNEL::HashMap<int,int>::const_iterator it(newNodeNumbersO2N.find(node));
2634 if(it!=newNodeNumbersO2N.end())
2640 std::ostringstream oss; oss << "MEDCouplingUMesh::renumberNodesInConn(map) : presence in connectivity for cell #" << i << " of node #" << node << " : Not in map !";
2641 throw INTERP_KERNEL::Exception(oss.str().c_str());
2645 _nodal_connec->declareAsNew();
2650 * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2651 * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2652 * This method is a generalization of shiftNodeNumbersInConn().
2653 * \warning This method performs no check of validity of new ids. **Use it with care !**
2654 * \param [in] newNodeNumbersO2N - a permutation array, of length \a
2655 * this->getNumberOfNodes(), in "Old to New" mode.
2656 * See \ref numbering for more info on renumbering modes.
2657 * \throw If the nodal connectivity of cells is not defined.
2659 * \if ENABLE_EXAMPLES
2660 * \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2661 * \ref py_mcumesh_renumberNodesInConn "Here is a Python example".
2664 void MEDCouplingUMesh::renumberNodesInConn(const int *newNodeNumbersO2N)
2666 checkConnectivityFullyDefined();
2667 int *conn=getNodalConnectivity()->getPointer();
2668 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2669 int nbOfCells(getNumberOfCells());
2670 for(int i=0;i<nbOfCells;i++)
2671 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2673 int& node=conn[iconn];
2674 if(node>=0)//avoid polyhedron separator
2676 node=newNodeNumbersO2N[node];
2679 _nodal_connec->declareAsNew();
2684 * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2685 * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2686 * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2688 * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2690 void MEDCouplingUMesh::shiftNodeNumbersInConn(int delta)
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
2705 _nodal_connec->declareAsNew();
2710 * This method operates a modification of the connectivity in \b this.
2711 * 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.
2712 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2713 * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2714 * 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
2715 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2716 * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2718 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2719 * As an another consequense after the call of this method \b this can be transiently non cohrent.
2721 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2722 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2723 * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ).
2725 void MEDCouplingUMesh::duplicateNodesInConn(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd, int offset)
2727 checkConnectivityFullyDefined();
2728 std::map<int,int> m;
2730 for(const int *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2732 int *conn=getNodalConnectivity()->getPointer();
2733 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2734 int nbOfCells=getNumberOfCells();
2735 for(int i=0;i<nbOfCells;i++)
2736 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2738 int& node=conn[iconn];
2739 if(node>=0)//avoid polyhedron separator
2741 std::map<int,int>::iterator it=m.find(node);
2750 * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2752 * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2753 * After the call of this method the number of cells remains the same as before.
2755 * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2756 * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2757 * be strictly in [0;this->getNumberOfCells()).
2759 * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2760 * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2761 * should be contained in[0;this->getNumberOfCells()).
2763 * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2766 void MEDCouplingUMesh::renumberCells(const int *old2NewBg, bool check)
2768 checkConnectivityFullyDefined();
2769 int nbCells=getNumberOfCells();
2770 const int *array=old2NewBg;
2772 array=DataArrayInt::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2774 const int *conn=_nodal_connec->getConstPointer();
2775 const int *connI=_nodal_connec_index->getConstPointer();
2776 MCAuto<DataArrayInt> o2n=DataArrayInt::New(); o2n->useArray(array,false,C_DEALLOC,nbCells,1);
2777 MCAuto<DataArrayInt> n2o=o2n->invertArrayO2N2N2O(nbCells);
2778 const int *n2oPtr=n2o->begin();
2779 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
2780 newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2781 newConn->copyStringInfoFrom(*_nodal_connec);
2782 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
2783 newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2784 newConnI->copyStringInfoFrom(*_nodal_connec_index);
2786 int *newC=newConn->getPointer();
2787 int *newCI=newConnI->getPointer();
2790 for(int i=0;i<nbCells;i++)
2793 int nbOfElts=connI[pos+1]-connI[pos];
2794 newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2799 setConnectivity(newConn,newConnI);
2801 free(const_cast<int *>(array));
2805 * Finds cells whose bounding boxes intersect a given bounding box.
2806 * \param [in] bbox - an array defining the bounding box via coordinates of its
2807 * extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2809 * \param [in] eps - a factor used to increase size of the bounding box of cell
2810 * before comparing it with \a bbox. This factor is multiplied by the maximal
2811 * extent of the bounding box of cell to produce an addition to this bounding box.
2812 * \return DataArrayInt * - a new instance of DataArrayInt holding ids for found
2813 * cells. The caller is to delete this array using decrRef() as it is no more
2815 * \throw If the coordinates array is not set.
2816 * \throw If the nodal connectivity of cells is not defined.
2818 * \if ENABLE_EXAMPLES
2819 * \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2820 * \ref py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2823 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2825 MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2826 if(getMeshDimension()==-1)
2828 elems->pushBackSilent(0);
2829 return elems.retn();
2831 int dim=getSpaceDimension();
2832 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2833 const int* conn = getNodalConnectivity()->getConstPointer();
2834 const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2835 const double* coords = getCoords()->getConstPointer();
2836 int nbOfCells=getNumberOfCells();
2837 for ( int ielem=0; ielem<nbOfCells;ielem++ )
2839 for (int i=0; i<dim; i++)
2841 elem_bb[i*2]=std::numeric_limits<double>::max();
2842 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2845 for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2847 int node= conn[inode];
2848 if(node>=0)//avoid polyhedron separator
2850 for (int idim=0; idim<dim; idim++)
2852 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2854 elem_bb[idim*2] = coords[node*dim+idim] ;
2856 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2858 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2863 if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2864 elems->pushBackSilent(ielem);
2866 return elems.retn();
2870 * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2871 * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2872 * added in 'elems' parameter.
2874 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2876 MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2877 if(getMeshDimension()==-1)
2879 elems->pushBackSilent(0);
2880 return elems.retn();
2882 int dim=getSpaceDimension();
2883 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2884 const int* conn = getNodalConnectivity()->getConstPointer();
2885 const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2886 const double* coords = getCoords()->getConstPointer();
2887 int nbOfCells=getNumberOfCells();
2888 for ( int ielem=0; ielem<nbOfCells;ielem++ )
2890 for (int i=0; i<dim; i++)
2892 elem_bb[i*2]=std::numeric_limits<double>::max();
2893 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2896 for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2898 int node= conn[inode];
2899 if(node>=0)//avoid polyhedron separator
2901 for (int idim=0; idim<dim; idim++)
2903 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2905 elem_bb[idim*2] = coords[node*dim+idim] ;
2907 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2909 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2914 if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
2915 elems->pushBackSilent(ielem);
2917 return elems.retn();
2921 * Returns a type of a cell by its id.
2922 * \param [in] cellId - the id of the cell of interest.
2923 * \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
2924 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2926 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(int cellId) const
2928 const int *ptI=_nodal_connec_index->getConstPointer();
2929 const int *pt=_nodal_connec->getConstPointer();
2930 if(cellId>=0 && cellId<(int)_nodal_connec_index->getNbOfElems()-1)
2931 return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2934 std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2935 throw INTERP_KERNEL::Exception(oss.str().c_str());
2940 * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2941 * This method does not throw exception if geometric type \a type is not in \a this.
2942 * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2943 * The coordinates array is not considered here.
2945 * \param [in] type the geometric type
2946 * \return cell ids in this having geometric type \a type.
2948 DataArrayInt *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2951 MCAuto<DataArrayInt> ret=DataArrayInt::New();
2953 checkConnectivityFullyDefined();
2954 int nbCells=getNumberOfCells();
2955 int mdim=getMeshDimension();
2956 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
2957 if(mdim!=(int)cm.getDimension())
2958 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
2959 const int *ptI=_nodal_connec_index->getConstPointer();
2960 const int *pt=_nodal_connec->getConstPointer();
2961 for(int i=0;i<nbCells;i++)
2963 if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
2964 ret->pushBackSilent(i);
2970 * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
2972 int MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2974 const int *ptI=_nodal_connec_index->getConstPointer();
2975 const int *pt=_nodal_connec->getConstPointer();
2976 int nbOfCells=getNumberOfCells();
2978 for(int i=0;i<nbOfCells;i++)
2979 if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
2985 * Returns the nodal connectivity of a given cell.
2986 * The separator of faces within polyhedron connectivity (-1) is not returned, thus
2987 * all returned node ids can be used in getCoordinatesOfNode().
2988 * \param [in] cellId - an id of the cell of interest.
2989 * \param [in,out] conn - a vector where the node ids are appended. It is not
2990 * cleared before the appending.
2991 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2993 void MEDCouplingUMesh::getNodeIdsOfCell(int cellId, std::vector<int>& conn) const
2995 const int *ptI=_nodal_connec_index->getConstPointer();
2996 const int *pt=_nodal_connec->getConstPointer();
2997 for(const int *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
3002 std::string MEDCouplingUMesh::simpleRepr() const
3004 static const char msg0[]="No coordinates specified !";
3005 std::ostringstream ret;
3006 ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
3007 ret << "Description of mesh : \"" << getDescription() << "\"\n";
3009 double tt=getTime(tmpp1,tmpp2);
3010 ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
3011 ret << "Iteration : " << tmpp1 << " Order : " << tmpp2 << "\n";
3013 { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
3015 { ret << " Mesh dimension has not been set or is invalid !"; }
3018 const int spaceDim=getSpaceDimension();
3019 ret << spaceDim << "\nInfo attached on space dimension : ";
3020 for(int i=0;i<spaceDim;i++)
3021 ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
3025 ret << msg0 << "\n";
3026 ret << "Number of nodes : ";
3028 ret << getNumberOfNodes() << "\n";
3030 ret << msg0 << "\n";
3031 ret << "Number of cells : ";
3032 if(_nodal_connec!=0 && _nodal_connec_index!=0)
3033 ret << getNumberOfCells() << "\n";
3035 ret << "No connectivity specified !" << "\n";
3036 ret << "Cell types present : ";
3037 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
3039 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
3040 ret << cm.getRepr() << " ";
3046 std::string MEDCouplingUMesh::advancedRepr() const
3048 std::ostringstream ret;
3049 ret << simpleRepr();
3050 ret << "\nCoordinates array : \n___________________\n\n";
3052 _coords->reprWithoutNameStream(ret);
3054 ret << "No array set !\n";
3055 ret << "\n\nConnectivity arrays : \n_____________________\n\n";
3056 reprConnectivityOfThisLL(ret);
3061 * This method returns a C++ code that is a dump of \a this.
3062 * This method will throw if this is not fully defined.
3064 std::string MEDCouplingUMesh::cppRepr() const
3066 static const char coordsName[]="coords";
3067 static const char connName[]="conn";
3068 static const char connIName[]="connI";
3069 checkFullyDefined();
3070 std::ostringstream ret; ret << "// coordinates" << std::endl;
3071 _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
3072 _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
3073 _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
3074 ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
3075 ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
3076 ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
3077 ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
3081 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
3083 std::ostringstream ret;
3084 reprConnectivityOfThisLL(ret);
3089 * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsability to deal with.
3090 * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
3091 * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
3094 * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
3095 * 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
3096 * with number of tuples set to 0, if not the array is taken as this in the returned instance.
3098 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(int spaceDim) const
3100 int mdim=getMeshDimension();
3102 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
3103 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
3104 MCAuto<DataArrayInt> tmp1,tmp2;
3105 bool needToCpyCT=true;
3108 tmp1=DataArrayInt::New(); tmp1->alloc(0,1);
3116 if(!_nodal_connec_index)
3118 tmp2=DataArrayInt::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
3123 tmp2=_nodal_connec_index;
3126 ret->setConnectivity(tmp1,tmp2,false);
3131 MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
3132 ret->setCoords(coords);
3135 ret->setCoords(_coords);
3139 void MEDCouplingUMesh::reprConnectivityOfThisLL(std::ostringstream& stream) const
3141 if(_nodal_connec!=0 && _nodal_connec_index!=0)
3143 int nbOfCells=getNumberOfCells();
3144 const int *c=_nodal_connec->getConstPointer();
3145 const int *ci=_nodal_connec_index->getConstPointer();
3146 for(int i=0;i<nbOfCells;i++)
3148 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[i]]);
3149 stream << "Cell #" << i << " " << cm.getRepr() << " : ";
3150 std::copy(c+ci[i]+1,c+ci[i+1],std::ostream_iterator<int>(stream," "));
3155 stream << "Connectivity not defined !\n";
3158 int MEDCouplingUMesh::getNumberOfNodesInCell(int cellId) const
3160 const int *ptI=_nodal_connec_index->getConstPointer();
3161 const int *pt=_nodal_connec->getConstPointer();
3162 if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
3163 return ptI[cellId+1]-ptI[cellId]-1;
3165 return (int)std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind2nd(std::not_equal_to<int>(),-1));
3169 * Returns types of cells of the specified part of \a this mesh.
3170 * This method avoids computing sub-mesh explicitely to get its types.
3171 * \param [in] begin - an array of cell ids of interest.
3172 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3173 * \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3174 * describing the cell types.
3175 * \throw If the coordinates array is not set.
3176 * \throw If the nodal connectivity of cells is not defined.
3177 * \sa getAllGeoTypes()
3179 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const int *begin, const int *end) const
3181 checkFullyDefined();
3182 std::set<INTERP_KERNEL::NormalizedCellType> ret;
3183 const int *conn=_nodal_connec->getConstPointer();
3184 const int *connIndex=_nodal_connec_index->getConstPointer();
3185 for(const int *w=begin;w!=end;w++)
3186 ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3191 * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3192 * Optionally updates
3193 * a set of types of cells constituting \a this mesh.
3194 * This method is for advanced users having prepared their connectivity before. For
3195 * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3196 * \param [in] conn - the nodal connectivity array.
3197 * \param [in] connIndex - the nodal connectivity index array.
3198 * \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3201 void MEDCouplingUMesh::setConnectivity(DataArrayInt *conn, DataArrayInt *connIndex, bool isComputingTypes)
3203 DataArrayInt::SetArrayIn(conn,_nodal_connec);
3204 DataArrayInt::SetArrayIn(connIndex,_nodal_connec_index);
3205 if(isComputingTypes)
3211 * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3212 * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3214 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCopy):MEDCouplingPointSet(other,deepCopy),_mesh_dim(other._mesh_dim),
3215 _nodal_connec(0),_nodal_connec_index(0),
3216 _types(other._types)
3218 if(other._nodal_connec)
3219 _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCopy);
3220 if(other._nodal_connec_index)
3221 _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCopy);
3224 MEDCouplingUMesh::~MEDCouplingUMesh()
3227 _nodal_connec->decrRef();
3228 if(_nodal_connec_index)
3229 _nodal_connec_index->decrRef();
3233 * Recomputes a set of cell types of \a this mesh. For more info see
3234 * \ref MEDCouplingUMeshNodalConnectivity.
3236 void MEDCouplingUMesh::computeTypes()
3238 ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3242 * This method checks that all arrays are set. If yes nothing done if no an exception is thrown.
3244 void MEDCouplingUMesh::checkFullyDefined() const
3246 if(!_nodal_connec_index || !_nodal_connec || !_coords)
3247 throw INTERP_KERNEL::Exception("Reverse nodal connectivity computation requires full connectivity and coordinates set in unstructured mesh.");
3251 * This method checks that all connectivity arrays are set. If yes nothing done if no an exception is thrown.
3253 void MEDCouplingUMesh::checkConnectivityFullyDefined() const
3255 if(!_nodal_connec_index || !_nodal_connec)
3256 throw INTERP_KERNEL::Exception("Reverse nodal connectivity computation requires full connectivity set in unstructured mesh.");
3260 * Returns a number of cells constituting \a this mesh.
3261 * \return int - the number of cells in \a this mesh.
3262 * \throw If the nodal connectivity of cells is not defined.
3264 int MEDCouplingUMesh::getNumberOfCells() const
3266 if(_nodal_connec_index)
3267 return _nodal_connec_index->getNumberOfTuples()-1;
3272 throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3276 * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3277 * mesh. For more info see \ref meshes.
3278 * \return int - the dimension of \a this mesh.
3279 * \throw If the mesh dimension is not defined using setMeshDimension().
3281 int MEDCouplingUMesh::getMeshDimension() const
3284 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3289 * Returns a length of the nodal connectivity array.
3290 * This method is for test reason. Normally the integer returned is not useable by
3291 * user. For more info see \ref MEDCouplingUMeshNodalConnectivity.
3292 * \return int - the length of the nodal connectivity array.
3294 int MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3296 return _nodal_connec->getNbOfElems();
3300 * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3302 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<int>& tinyInfo, std::vector<std::string>& littleStrings) const
3304 MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3305 tinyInfo.push_back(getMeshDimension());
3306 tinyInfo.push_back(getNumberOfCells());
3308 tinyInfo.push_back(getNodalConnectivityArrayLen());
3310 tinyInfo.push_back(-1);
3314 * First step of unserialization process.
3316 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<int>& tinyInfo) const
3318 return tinyInfo[6]<=0;
3322 * Second step of serialization process.
3323 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3326 * \param littleStrings
3328 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<int>& tinyInfo, DataArrayInt *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3330 MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3332 a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3336 * Third and final step of serialization process.
3338 void MEDCouplingUMesh::serialize(DataArrayInt *&a1, DataArrayDouble *&a2) const
3340 MEDCouplingPointSet::serialize(a1,a2);
3341 if(getMeshDimension()>-1)
3343 a1=DataArrayInt::New();
3344 a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3345 int *ptA1=a1->getPointer();
3346 const int *conn=getNodalConnectivity()->getConstPointer();
3347 const int *index=getNodalConnectivityIndex()->getConstPointer();
3348 ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3349 std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3356 * Second and final unserialization process.
3357 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3359 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<int>& tinyInfo, const DataArrayInt *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3361 MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3362 setMeshDimension(tinyInfo[5]);
3366 const int *recvBuffer=a1->getConstPointer();
3367 MCAuto<DataArrayInt> myConnecIndex=DataArrayInt::New();
3368 myConnecIndex->alloc(tinyInfo[6]+1,1);
3369 std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3370 MCAuto<DataArrayInt> myConnec=DataArrayInt::New();
3371 myConnec->alloc(tinyInfo[7],1);
3372 std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3373 setConnectivity(myConnec, myConnecIndex);
3378 * This is the low algorithm of MEDCouplingUMesh::buildPartOfMySelfSlice.
3379 * CellIds are given using range specified by a start an end and step.
3381 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice(int start, int end, int step) const
3383 checkFullyDefined();
3384 int ncell=getNumberOfCells();
3385 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New();
3386 ret->_mesh_dim=_mesh_dim;
3387 ret->setCoords(_coords);
3388 int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice : ");
3389 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(newNbOfCells+1,1);
3390 int *newConnIPtr=newConnI->getPointer(); *newConnIPtr=0;
3392 const int *conn=_nodal_connec->getConstPointer();
3393 const int *connIndex=_nodal_connec_index->getConstPointer();
3394 for(int i=0;i<newNbOfCells;i++,newConnIPtr++,work+=step)
3396 if(work>=0 && work<ncell)
3398 newConnIPtr[1]=newConnIPtr[0]+connIndex[work+1]-connIndex[work];
3402 std::ostringstream oss; oss << "MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice : On pos #" << i << " input cell id =" << work << " should be in [0," << ncell << ") !";
3403 throw INTERP_KERNEL::Exception(oss.str().c_str());
3406 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(newConnIPtr[0],1);
3407 int *newConnPtr=newConn->getPointer();
3408 std::set<INTERP_KERNEL::NormalizedCellType> types;
3410 for(int i=0;i<newNbOfCells;i++,newConnIPtr++,work+=step)
3412 types.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[work]]);
3413 newConnPtr=std::copy(conn+connIndex[work],conn+connIndex[work+1],newConnPtr);
3415 ret->setConnectivity(newConn,newConnI,false);
3417 ret->copyTinyInfoFrom(this);
3422 * This is the low algorithm of MEDCouplingUMesh::buildPartOfMySelf.
3423 * Keeps from \a this only cells which constituing point id are in the ids specified by [ \a begin,\a end ).
3424 * The return newly allocated mesh will share the same coordinates as \a this.
3426 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfKeepCoords(const int *begin, const int *end) const
3428 checkConnectivityFullyDefined();
3429 int ncell=getNumberOfCells();
3430 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New();
3431 ret->_mesh_dim=_mesh_dim;
3432 ret->setCoords(_coords);
3433 std::size_t nbOfElemsRet=std::distance(begin,end);
3434 int *connIndexRet=(int *)malloc((nbOfElemsRet+1)*sizeof(int));
3436 const int *conn=_nodal_connec->getConstPointer();
3437 const int *connIndex=_nodal_connec_index->getConstPointer();
3439 for(const int *work=begin;work!=end;work++,newNbring++)
3441 if(*work>=0 && *work<ncell)
3442 connIndexRet[newNbring+1]=connIndexRet[newNbring]+connIndex[*work+1]-connIndex[*work];
3446 std::ostringstream oss; oss << "MEDCouplingUMesh::buildPartOfMySelfKeepCoords : On pos #" << std::distance(begin,work) << " input cell id =" << *work << " should be in [0," << ncell << ") !";
3447 throw INTERP_KERNEL::Exception(oss.str().c_str());
3450 int *connRet=(int *)malloc(connIndexRet[nbOfElemsRet]*sizeof(int));
3451 int *connRetWork=connRet;
3452 std::set<INTERP_KERNEL::NormalizedCellType> types;
3453 for(const int *work=begin;work!=end;work++)
3455 types.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*work]]);
3456 connRetWork=std::copy(conn+connIndex[*work],conn+connIndex[*work+1],connRetWork);
3458 MCAuto<DataArrayInt> connRetArr=DataArrayInt::New();
3459 connRetArr->useArray(connRet,true,C_DEALLOC,connIndexRet[nbOfElemsRet],1);
3460 MCAuto<DataArrayInt> connIndexRetArr=DataArrayInt::New();
3461 connIndexRetArr->useArray(connIndexRet,true,C_DEALLOC,(int)nbOfElemsRet+1,1);
3462 ret->setConnectivity(connRetArr,connIndexRetArr,false);
3464 ret->copyTinyInfoFrom(this);
3469 * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3471 * For 1D cells, the returned field contains lengths.<br>
3472 * For 2D cells, the returned field contains areas.<br>
3473 * For 3D cells, the returned field contains volumes.
3474 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3475 * orientation, i.e. the volume is always positive.
3476 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3477 * and one time . The caller is to delete this field using decrRef() as it is no
3480 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3482 std::string name="MeasureOfMesh_";
3484 int nbelem=getNumberOfCells();
3485 MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3486 field->setName(name);
3487 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3488 array->alloc(nbelem,1);
3489 double *area_vol=array->getPointer();
3490 field->setArray(array) ; array=0;
3491 field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3492 field->synchronizeTimeWithMesh();
3493 if(getMeshDimension()!=-1)
3496 INTERP_KERNEL::NormalizedCellType type;
3497 int dim_space=getSpaceDimension();
3498 const double *coords=getCoords()->getConstPointer();
3499 const int *connec=getNodalConnectivity()->getConstPointer();
3500 const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3501 for(int iel=0;iel<nbelem;iel++)
3503 ipt=connec_index[iel];
3504 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3505 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);
3508 std::transform(area_vol,area_vol+nbelem,area_vol,std::ptr_fun<double,double>(fabs));
3512 area_vol[0]=std::numeric_limits<double>::max();
3514 return field.retn();
3518 * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3520 * For 1D cells, the returned array contains lengths.<br>
3521 * For 2D cells, the returned array contains areas.<br>
3522 * For 3D cells, the returned array contains volumes.
3523 * This method avoids building explicitly a part of \a this mesh to perform the work.
3524 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3525 * orientation, i.e. the volume is always positive.
3526 * \param [in] begin - an array of cell ids of interest.
3527 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3528 * \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3529 * delete this array using decrRef() as it is no more needed.
3531 * \if ENABLE_EXAMPLES
3532 * \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3533 * \ref py_mcumesh_getPartMeasureField "Here is a Python example".
3535 * \sa getMeasureField()
3537 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const int *begin, const int *end) const
3539 std::string name="PartMeasureOfMesh_";
3541 int nbelem=(int)std::distance(begin,end);
3542 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3543 array->setName(name);
3544 array->alloc(nbelem,1);
3545 double *area_vol=array->getPointer();
3546 if(getMeshDimension()!=-1)
3549 INTERP_KERNEL::NormalizedCellType type;
3550 int dim_space=getSpaceDimension();
3551 const double *coords=getCoords()->getConstPointer();
3552 const int *connec=getNodalConnectivity()->getConstPointer();
3553 const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3554 for(const int *iel=begin;iel!=end;iel++)
3556 ipt=connec_index[*iel];
3557 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3558 *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<int,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3561 std::transform(array->getPointer(),area_vol,array->getPointer(),std::ptr_fun<double,double>(fabs));
3565 area_vol[0]=std::numeric_limits<double>::max();
3567 return array.retn();
3571 * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3572 * \a this one. The returned field contains the dual cell volume for each corresponding
3573 * node in \a this mesh. In other words, the field returns the getMeasureField() of
3574 * the dual mesh in P1 sens of \a this.<br>
3575 * For 1D cells, the returned field contains lengths.<br>
3576 * For 2D cells, the returned field contains areas.<br>
3577 * For 3D cells, the returned field contains volumes.
3578 * This method is useful to check "P1*" conservative interpolators.
3579 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3580 * orientation, i.e. the volume is always positive.
3581 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3582 * nodes and one time. The caller is to delete this array using decrRef() as
3583 * it is no more needed.
3585 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3587 MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3588 std::string name="MeasureOnNodeOfMesh_";
3590 int nbNodes=getNumberOfNodes();
3591 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3592 double cst=1./((double)getMeshDimension()+1.);
3593 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3594 array->alloc(nbNodes,1);
3595 double *valsToFill=array->getPointer();
3596 std::fill(valsToFill,valsToFill+nbNodes,0.);
3597 const double *values=tmp->getArray()->getConstPointer();
3598 MCAuto<DataArrayInt> da=DataArrayInt::New();
3599 MCAuto<DataArrayInt> daInd=DataArrayInt::New();
3600 getReverseNodalConnectivity(da,daInd);
3601 const int *daPtr=da->getConstPointer();
3602 const int *daIPtr=daInd->getConstPointer();
3603 for(int i=0;i<nbNodes;i++)
3604 for(const int *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3605 valsToFill[i]+=cst*values[*cell];
3607 ret->setArray(array);
3612 * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3613 * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3614 * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3615 * and are normalized.
3616 * <br> \a this can be either
3617 * - a 2D mesh in 2D or 3D space or
3618 * - an 1D mesh in 2D space.
3620 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3621 * cells and one time. The caller is to delete this field using decrRef() as
3622 * it is no more needed.
3623 * \throw If the nodal connectivity of cells is not defined.
3624 * \throw If the coordinates array is not set.
3625 * \throw If the mesh dimension is not set.
3626 * \throw If the mesh and space dimension is not as specified above.
3628 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3630 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3631 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3632 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3633 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3634 int nbOfCells=getNumberOfCells();
3635 int nbComp=getMeshDimension()+1;
3636 array->alloc(nbOfCells,nbComp);
3637 double *vals=array->getPointer();
3638 const int *connI=_nodal_connec_index->getConstPointer();
3639 const int *conn=_nodal_connec->getConstPointer();
3640 const double *coords=_coords->getConstPointer();
3641 if(getMeshDimension()==2)
3643 if(getSpaceDimension()==3)
3645 MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3646 const double *locPtr=loc->getConstPointer();
3647 for(int i=0;i<nbOfCells;i++,vals+=3)
3649 int offset=connI[i];
3650 INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3651 double n=INTERP_KERNEL::norm<3>(vals);
3652 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3657 MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3658 const double *isAbsPtr=isAbs->getArray()->begin();
3659 for(int i=0;i<nbOfCells;i++,isAbsPtr++)
3660 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3663 else//meshdimension==1
3666 for(int i=0;i<nbOfCells;i++)
3668 int offset=connI[i];
3669 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3670 double n=INTERP_KERNEL::norm<2>(tmp);
3671 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3676 ret->setArray(array);
3678 ret->synchronizeTimeWithSupport();
3683 * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3684 * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3685 * and are normalized.
3686 * <br> \a this can be either
3687 * - a 2D mesh in 2D or 3D space or
3688 * - an 1D mesh in 2D space.
3690 * This method avoids building explicitly a part of \a this mesh to perform the work.
3691 * \param [in] begin - an array of cell ids of interest.
3692 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3693 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3694 * cells and one time. The caller is to delete this field using decrRef() as
3695 * it is no more needed.
3696 * \throw If the nodal connectivity of cells is not defined.
3697 * \throw If the coordinates array is not set.
3698 * \throw If the mesh dimension is not set.
3699 * \throw If the mesh and space dimension is not as specified above.
3700 * \sa buildOrthogonalField()
3702 * \if ENABLE_EXAMPLES
3703 * \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3704 * \ref py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3707 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const int *begin, const int *end) const
3709 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3710 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3711 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3712 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3713 std::size_t nbelems=std::distance(begin,end);
3714 int nbComp=getMeshDimension()+1;
3715 array->alloc((int)nbelems,nbComp);
3716 double *vals=array->getPointer();
3717 const int *connI=_nodal_connec_index->getConstPointer();
3718 const int *conn=_nodal_connec->getConstPointer();
3719 const double *coords=_coords->getConstPointer();
3720 if(getMeshDimension()==2)
3722 if(getSpaceDimension()==3)
3724 MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3725 const double *locPtr=loc->getConstPointer();
3726 for(const int *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3728 int offset=connI[*i];
3729 INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3730 double n=INTERP_KERNEL::norm<3>(vals);
3731 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3736 for(std::size_t i=0;i<nbelems;i++)
3737 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3740 else//meshdimension==1
3743 for(const int *i=begin;i!=end;i++)
3745 int offset=connI[*i];
3746 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3747 double n=INTERP_KERNEL::norm<2>(tmp);
3748 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3753 ret->setArray(array);
3755 ret->synchronizeTimeWithSupport();
3760 * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3761 * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3762 * and are \b not normalized.
3763 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3764 * cells and one time. The caller is to delete this field using decrRef() as
3765 * it is no more needed.
3766 * \throw If the nodal connectivity of cells is not defined.
3767 * \throw If the coordinates array is not set.
3768 * \throw If \a this->getMeshDimension() != 1.
3769 * \throw If \a this mesh includes cells of type other than SEG2.
3771 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3773 if(getMeshDimension()!=1)
3774 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3775 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3776 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3777 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3778 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3779 int nbOfCells=getNumberOfCells();
3780 int spaceDim=getSpaceDimension();
3781 array->alloc(nbOfCells,spaceDim);
3782 double *pt=array->getPointer();
3783 const double *coo=getCoords()->getConstPointer();
3784 std::vector<int> conn;
3786 for(int i=0;i<nbOfCells;i++)
3789 getNodeIdsOfCell(i,conn);
3790 pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3792 ret->setArray(array);
3794 ret->synchronizeTimeWithSupport();
3799 * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3800 * returns a new DataArrayInt, of length equal to the number of 2D cells in the result
3801 * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3802 * from. If a result face is shared by two 3D cells, then the face in included twice in
3804 * \param [in] origin - 3 components of a point defining location of the plane.
3805 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3806 * must be greater than 1e-6.
3807 * \param [in] eps - half-thickness of the plane.
3808 * \param [out] cellIds - a new instance of DataArrayInt holding ids of 3D cells
3809 * producing correspondent 2D cells. The caller is to delete this array
3810 * using decrRef() as it is no more needed.
3811 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3812 * not share the node coordinates array with \a this mesh. The caller is to
3813 * delete this mesh using decrRef() as it is no more needed.
3814 * \throw If the coordinates array is not set.
3815 * \throw If the nodal connectivity of cells is not defined.
3816 * \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3817 * \throw If magnitude of \a vec is less than 1e-6.
3818 * \throw If the plane does not intersect any 3D cell of \a this mesh.
3819 * \throw If \a this includes quadratic cells.
3821 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3823 checkFullyDefined();
3824 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3825 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3826 MCAuto<DataArrayInt> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3827 if(candidates->empty())
3828 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3829 std::vector<int> nodes;
3830 DataArrayInt *cellIds1D=0;
3831 MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3832 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3833 MCAuto<DataArrayInt> desc1=DataArrayInt::New(),desc2=DataArrayInt::New();
3834 MCAuto<DataArrayInt> descIndx1=DataArrayInt::New(),descIndx2=DataArrayInt::New();
3835 MCAuto<DataArrayInt> revDesc1=DataArrayInt::New(),revDesc2=DataArrayInt::New();
3836 MCAuto<DataArrayInt> revDescIndx1=DataArrayInt::New(),revDescIndx2=DataArrayInt::New();
3837 MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3838 revDesc2=0; revDescIndx2=0;
3839 MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3840 revDesc1=0; revDescIndx1=0;
3841 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3842 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3844 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3845 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3847 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3848 std::vector< std::pair<int,int> > cut3DSurf(mDesc2->getNumberOfCells());
3849 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3850 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3851 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3852 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New());
3853 connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3854 subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3855 if(cellIds2->empty())
3856 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3857 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3858 ret->setCoords(mDesc1->getCoords());
3859 ret->setConnectivity(conn,connI,true);
3860 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3865 * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3866 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
3867 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3869 * \param [in] origin - 3 components of a point defining location of the plane.
3870 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3871 * must be greater than 1e-6.
3872 * \param [in] eps - half-thickness of the plane.
3873 * \param [out] cellIds - a new instance of DataArrayInt holding ids of faces
3874 * producing correspondent segments. The caller is to delete this array
3875 * using decrRef() as it is no more needed.
3876 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3877 * mesh in 3D space. This mesh does not share the node coordinates array with
3878 * \a this mesh. The caller is to delete this mesh using decrRef() as it is
3880 * \throw If the coordinates array is not set.
3881 * \throw If the nodal connectivity of cells is not defined.
3882 * \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3883 * \throw If magnitude of \a vec is less than 1e-6.
3884 * \throw If the plane does not intersect any 2D cell of \a this mesh.
3885 * \throw If \a this includes quadratic cells.
3887 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3889 checkFullyDefined();
3890 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3891 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3892 MCAuto<DataArrayInt> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3893 if(candidates->empty())
3894 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3895 std::vector<int> nodes;
3896 DataArrayInt *cellIds1D=0;
3897 MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3898 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3899 MCAuto<DataArrayInt> desc1=DataArrayInt::New();
3900 MCAuto<DataArrayInt> descIndx1=DataArrayInt::New();
3901 MCAuto<DataArrayInt> revDesc1=DataArrayInt::New();
3902 MCAuto<DataArrayInt> revDescIndx1=DataArrayInt::New();
3903 MCAuto<MEDCouplingUMesh> mDesc1=subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3904 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3905 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3907 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3908 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3910 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3911 int ncellsSub=subMesh->getNumberOfCells();
3912 std::vector< std::pair<int,int> > cut3DSurf(ncellsSub);
3913 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3914 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3915 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3916 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New()); connI->pushBackSilent(0);
3918 const int *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3919 const int *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3920 for(int i=0;i<ncellsSub;i++)
3922 if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3924 if(cut3DSurf[i].first!=-2)
3926 conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3927 connI->pushBackSilent(conn->getNumberOfTuples());
3928 cellIds2->pushBackSilent(i);
3932 int cellId3DSurf=cut3DSurf[i].second;
3933 int offset=nodalI[cellId3DSurf]+1;
3934 int nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3935 for(int j=0;j<nbOfEdges;j++)
3937 conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3938 connI->pushBackSilent(conn->getNumberOfTuples());
3939 cellIds2->pushBackSilent(cellId3DSurf);
3944 if(cellIds2->empty())
3945 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3946 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3947 ret->setCoords(mDesc1->getCoords());
3948 ret->setConnectivity(conn,connI,true);
3949 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3954 * Finds cells whose bounding boxes intersect a given plane.
3955 * \param [in] origin - 3 components of a point defining location of the plane.
3956 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3957 * must be greater than 1e-6.
3958 * \param [in] eps - half-thickness of the plane.
3959 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of the found
3960 * cells. The caller is to delete this array using decrRef() as it is no more
3962 * \throw If the coordinates array is not set.
3963 * \throw If the nodal connectivity of cells is not defined.
3964 * \throw If \a this->getSpaceDimension() != 3.
3965 * \throw If magnitude of \a vec is less than 1e-6.
3966 * \sa buildSlice3D()
3968 DataArrayInt *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
3970 checkFullyDefined();
3971 if(getSpaceDimension()!=3)
3972 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
3973 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
3975 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
3977 vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
3978 double angle=acos(vec[2]/normm);
3979 MCAuto<DataArrayInt> cellIds;
3983 MCAuto<DataArrayDouble> coo=_coords->deepCopy();
3984 double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
3985 if(normm2/normm>1e-6)
3986 MEDCouplingPointSet::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer());
3987 MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
3989 mw->getBoundingBox(bbox);
3990 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3991 cellIds=mw->getCellsInBoundingBox(bbox,eps);
3995 getBoundingBox(bbox);
3996 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3997 cellIds=getCellsInBoundingBox(bbox,eps);
3999 return cellIds.retn();
4003 * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
4004 * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
4005 * No consideration of coordinate is done by this method.
4006 * 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)
4007 * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be usefull.
4009 bool MEDCouplingUMesh::isContiguous1D() const
4011 if(getMeshDimension()!=1)
4012 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
4013 int nbCells=getNumberOfCells();
4015 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
4016 const int *connI=_nodal_connec_index->getConstPointer();
4017 const int *conn=_nodal_connec->getConstPointer();
4018 int ref=conn[connI[0]+2];
4019 for(int i=1;i<nbCells;i++)
4021 if(conn[connI[i]+1]!=ref)
4023 ref=conn[connI[i]+2];
4029 * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
4030 * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
4031 * \param pt reference point of the line
4032 * \param v normalized director vector of the line
4033 * \param eps max precision before throwing an exception
4034 * \param res output of size this->getNumberOfCells
4036 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
4038 if(getMeshDimension()!=1)
4039 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
4040 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
4041 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
4042 if(getSpaceDimension()!=3)
4043 throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
4044 MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
4045 const double *fPtr=f->getArray()->getConstPointer();
4047 for(int i=0;i<getNumberOfCells();i++)
4049 const double *tmp1=fPtr+3*i;
4050 tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
4051 tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
4052 tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
4053 double n1=INTERP_KERNEL::norm<3>(tmp);
4054 n1/=INTERP_KERNEL::norm<3>(tmp1);
4056 throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
4058 const double *coo=getCoords()->getConstPointer();
4059 for(int i=0;i<getNumberOfNodes();i++)
4061 std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
4062 std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
4063 res[i]=std::accumulate(tmp,tmp+3,0.);
4068 * 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.
4069 * \a this is expected to be a mesh so that its space dimension is equal to its
4070 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4071 * 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).
4073 * 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
4074 * 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).
4075 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4077 * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
4078 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4080 * \param [in] ptBg the start pointer (included) of the coordinates of the point
4081 * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
4082 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4083 * \return the positive value of the distance.
4084 * \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
4086 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
4088 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, int& cellId) const
4090 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4091 if(meshDim!=spaceDim-1)
4092 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
4093 if(meshDim!=2 && meshDim!=1)
4094 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
4095 checkFullyDefined();
4096 if((int)std::distance(ptBg,ptEnd)!=spaceDim)
4097 { std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoint : input point has to have dimension equal to the space dimension of this (" << spaceDim << ") !"; throw INTERP_KERNEL::Exception(oss.str().c_str()); }
4098 DataArrayInt *ret1=0;
4099 MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,C_DEALLOC,1,spaceDim);
4100 MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
4101 MCAuto<DataArrayInt> ret1Safe(ret1);
4102 cellId=*ret1Safe->begin();
4103 return *ret0->begin();
4107 * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
4108 * to \a this and the first \a cellId in \a this corresponding to the returned distance.
4109 * 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
4110 * 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).
4111 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4113 * \a this is expected to be a mesh so that its space dimension is equal to its
4114 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4115 * 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).
4117 * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
4118 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4120 * \param [in] pts the list of points in which each tuple represents a point
4121 * \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.
4122 * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
4123 * \throw if number of components of \a pts is not equal to the space dimension.
4124 * \throw if mesh dimension of \a this is not equal to space dimension - 1.
4125 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
4127 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayInt *& cellIds) const
4130 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
4131 pts->checkAllocated();
4132 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4133 if(meshDim!=spaceDim-1)
4134 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
4135 if(meshDim!=2 && meshDim!=1)
4136 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
4137 if(pts->getNumberOfComponents()!=spaceDim)
4139 std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
4140 throw INTERP_KERNEL::Exception(oss.str().c_str());
4142 checkFullyDefined();
4143 int nbCells=getNumberOfCells();
4145 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
4146 int nbOfPts=pts->getNumberOfTuples();
4147 MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
4148 MCAuto<DataArrayInt> ret1=DataArrayInt::New(); ret1->alloc(nbOfPts,1);
4149 const int *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
4150 double *ret0Ptr=ret0->getPointer(); int *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
4151 MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
4152 const double *bbox(bboxArr->begin());
4157 BBTreeDst<3> myTree(bbox,0,0,nbCells);
4158 for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
4160 double x=std::numeric_limits<double>::max();
4161 std::vector<int> elems;
4162 myTree.getMinDistanceOfMax(ptsPtr,x);
4163 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4164 DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4170 BBTreeDst<2> myTree(bbox,0,0,nbCells);
4171 for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4173 double x=std::numeric_limits<double>::max();
4174 std::vector<int> elems;
4175 myTree.getMinDistanceOfMax(ptsPtr,x);
4176 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4177 DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4182 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4184 cellIds=ret1.retn();
4191 * \param [in] pt the start pointer (included) of the coordinates of the point
4192 * \param [in] cellIdsBg the start pointer (included) of cellIds
4193 * \param [in] cellIdsEnd the end pointer (excluded) of cellIds
4194 * \param [in] nc nodal connectivity
4195 * \param [in] ncI nodal connectivity index
4196 * \param [in,out] ret0 the min distance between \a this and the external input point
4197 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4198 * \sa MEDCouplingUMesh::distanceToPoint, MEDCouplingUMesh::distanceToPoints
4200 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)
4203 ret0=std::numeric_limits<double>::max();
4204 for(const int *zeCell=cellIdsBg;zeCell!=cellIdsEnd;zeCell++)
4206 switch((INTERP_KERNEL::NormalizedCellType)nc[ncI[*zeCell]])
4208 case INTERP_KERNEL::NORM_TRI3:
4210 double tmp=INTERP_KERNEL::DistanceFromPtToTriInSpaceDim3(pt,coords+3*nc[ncI[*zeCell]+1],coords+3*nc[ncI[*zeCell]+2],coords+3*nc[ncI[*zeCell]+3]);
4212 { ret0=tmp; cellId=*zeCell; }
4215 case INTERP_KERNEL::NORM_QUAD4:
4216 case INTERP_KERNEL::NORM_POLYGON:
4218 double tmp=INTERP_KERNEL::DistanceFromPtToPolygonInSpaceDim3(pt,nc+ncI[*zeCell]+1,nc+ncI[*zeCell+1],coords);
4220 { ret0=tmp; cellId=*zeCell; }
4224 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint3DSurfAlg : not managed cell type ! Supporting TRI3, QUAD4 and POLYGON !");
4230 * \param [in] pt the start pointer (included) of the coordinates of the point
4231 * \param [in] cellIdsBg the start pointer (included) of cellIds
4232 * \param [in] cellIdsEnd the end pointer (excluded) of cellIds
4233 * \param [in] nc nodal connectivity
4234 * \param [in] ncI nodal connectivity index
4235 * \param [in,out] ret0 the min distance between \a this and the external input point
4236 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4237 * \sa MEDCouplingUMesh::distanceToPoint, MEDCouplingUMesh::distanceToPoints
4239 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)
4242 ret0=std::numeric_limits<double>::max();
4243 for(const int *zeCell=cellIdsBg;zeCell!=cellIdsEnd;zeCell++)
4245 switch((INTERP_KERNEL::NormalizedCellType)nc[ncI[*zeCell]])
4247 case INTERP_KERNEL::NORM_SEG2:
4249 std::size_t uselessEntry=0;
4250 double tmp=INTERP_KERNEL::SquareDistanceFromPtToSegInSpaceDim2(pt,coords+2*nc[ncI[*zeCell]+1],coords+2*nc[ncI[*zeCell]+2],uselessEntry);
4253 { ret0=tmp; cellId=*zeCell; }
4257 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint2DCurveAlg : not managed cell type ! Supporting SEG2 !");
4264 * Finds cells in contact with a ball (i.e. a point with precision).
4265 * 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.
4266 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4268 * \warning This method is suitable if the caller intends to evaluate only one
4269 * point, for more points getCellsContainingPoints() is recommended as it is
4271 * \param [in] pos - array of coordinates of the ball central point.
4272 * \param [in] eps - ball radius.
4273 * \return int - a smallest id of cells being in contact with the ball, -1 in case
4274 * if there are no such cells.
4275 * \throw If the coordinates array is not set.
4276 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4278 int MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4280 std::vector<int> elts;
4281 getCellsContainingPoint(pos,eps,elts);
4284 return elts.front();
4288 * Finds cells in contact with a ball (i.e. a point with precision).
4289 * 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.
4290 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4291 * \warning This method is suitable if the caller intends to evaluate only one
4292 * point, for more points getCellsContainingPoints() is recommended as it is
4294 * \param [in] pos - array of coordinates of the ball central point.
4295 * \param [in] eps - ball radius.
4296 * \param [out] elts - vector returning ids of the found cells. It is cleared
4297 * before inserting ids.
4298 * \throw If the coordinates array is not set.
4299 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4301 * \if ENABLE_EXAMPLES
4302 * \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4303 * \ref py_mcumesh_getCellsContainingPoint "Here is a Python example".
4306 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<int>& elts) const
4308 MCAuto<DataArrayInt> eltsUg,eltsIndexUg;
4309 getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4310 elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4315 namespace MEDCoupling
4317 template<const int SPACEDIMM>
4321 static const int MY_SPACEDIM=SPACEDIMM;
4322 static const int MY_MESHDIM=8;
4323 typedef int MyConnType;
4324 static const INTERP_KERNEL::NumberingPolicy My_numPol=INTERP_KERNEL::ALL_C_MODE;
4326 // useless, but for windows compilation ...
4327 const double* getCoordinatesPtr() const { return 0; }
4328 const int* getConnectivityPtr() const { return 0; }
4329 const int* getConnectivityIndexPtr() const { return 0; }
4330 INTERP_KERNEL::NormalizedCellType getTypeOfElement(int) const { return (INTERP_KERNEL::NormalizedCellType)0; }
4334 INTERP_KERNEL::Edge *MEDCouplingUMeshBuildQPFromEdge2(INTERP_KERNEL::NormalizedCellType typ, const int *bg, const double *coords2D, std::map< MCAuto<INTERP_KERNEL::Node>,int>& m)
4336 INTERP_KERNEL::Edge *ret(0);
4337 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]));
4338 m[n0]=bg[0]; m[n1]=bg[1];
4341 case INTERP_KERNEL::NORM_SEG2:
4343 ret=new INTERP_KERNEL::EdgeLin(n0,n1);
4346 case INTERP_KERNEL::NORM_SEG3:
4348 INTERP_KERNEL::Node *n2(new INTERP_KERNEL::Node(coords2D[2*bg[2]],coords2D[2*bg[2]+1])); m[n2]=bg[2];
4349 INTERP_KERNEL::EdgeLin *e1(new INTERP_KERNEL::EdgeLin(n0,n2)),*e2(new INTERP_KERNEL::EdgeLin(n2,n1));
4350 INTERP_KERNEL::SegSegIntersector inters(*e1,*e2);
4351 // is the SEG3 degenerated, and thus can be reduced to a SEG2?
4352 bool colinearity(inters.areColinears());
4353 delete e1; delete e2;
4355 { ret=new INTERP_KERNEL::EdgeLin(n0,n1); }
4357 { ret=new INTERP_KERNEL::EdgeArcCircle(n0,n2,n1); }
4361 throw INTERP_KERNEL::Exception("MEDCouplingUMeshBuildQPFromEdge2 : Expecting a mesh with spaceDim==2 and meshDim==1 !");
4366 INTERP_KERNEL::Edge *MEDCouplingUMeshBuildQPFromEdge(INTERP_KERNEL::NormalizedCellType typ, std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >& mapp2, const int *bg)
4368 INTERP_KERNEL::Edge *ret=0;
4371 case INTERP_KERNEL::NORM_SEG2:
4373 ret=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[1]].first);
4376 case INTERP_KERNEL::NORM_SEG3:
4378 INTERP_KERNEL::EdgeLin *e1=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[2]].first);
4379 INTERP_KERNEL::EdgeLin *e2=new INTERP_KERNEL::EdgeLin(mapp2[bg[2]].first,mapp2[bg[1]].first);
4380 INTERP_KERNEL::SegSegIntersector inters(*e1,*e2);
4381 // is the SEG3 degenerated, and thus can be reduced to a SEG2?
4382 bool colinearity=inters.areColinears();
4383 delete e1; delete e2;
4385 ret=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[1]].first);
4387 ret=new INTERP_KERNEL::EdgeArcCircle(mapp2[bg[0]].first,mapp2[bg[2]].first,mapp2[bg[1]].first);
4388 mapp2[bg[2]].second=false;
4392 throw INTERP_KERNEL::Exception("MEDCouplingUMeshBuildQPFromEdge : Expecting a mesh with spaceDim==2 and meshDim==1 !");
4398 * This method creates a sub mesh in Geometric2D DS. The sub mesh is composed by the sub set of cells in 'candidates' taken from
4399 * the global mesh 'mDesc'.
4400 * The input mesh 'mDesc' must be so that mDim==1 and spaceDim==2.
4401 * 'mapp' returns a mapping between local numbering in submesh (represented by a Node*) and the global node numbering in 'mDesc'.
4403 INTERP_KERNEL::QuadraticPolygon *MEDCouplingUMeshBuildQPFromMesh(const MEDCouplingUMesh *mDesc, const std::vector<int>& candidates,
4404 std::map<INTERP_KERNEL::Node *,int>& mapp)
4407 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.
4408 const double *coo=mDesc->getCoords()->getConstPointer();
4409 const int *c=mDesc->getNodalConnectivity()->getConstPointer();
4410 const int *cI=mDesc->getNodalConnectivityIndex()->getConstPointer();
4412 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
4413 s.insert(c+cI[*it]+1,c+cI[(*it)+1]);
4414 for(std::set<int>::const_iterator it2=s.begin();it2!=s.end();it2++)
4416 INTERP_KERNEL::Node *n=new INTERP_KERNEL::Node(coo[2*(*it2)],coo[2*(*it2)+1]);
4417 mapp2[*it2]=std::pair<INTERP_KERNEL::Node *,bool>(n,true);
4419 INTERP_KERNEL::QuadraticPolygon *ret=new INTERP_KERNEL::QuadraticPolygon;
4420 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
4422 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[*it]];
4423 ret->pushBack(MEDCouplingUMeshBuildQPFromEdge(typ,mapp2,c+cI[*it]+1));
4425 for(std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >::const_iterator it2=mapp2.begin();it2!=mapp2.end();it2++)
4427 if((*it2).second.second)
4428 mapp[(*it2).second.first]=(*it2).first;
4429 ((*it2).second.first)->decrRef();
4434 INTERP_KERNEL::Node *MEDCouplingUMeshBuildQPNode(int nodeId, const double *coo1, int offset1, const double *coo2, int offset2, const std::vector<double>& addCoo)
4438 int locId=nodeId-offset2;
4439 return new INTERP_KERNEL::Node(addCoo[2*locId],addCoo[2*locId+1]);
4443 int locId=nodeId-offset1;
4444 return new INTERP_KERNEL::Node(coo2[2*locId],coo2[2*locId+1]);
4446 return new INTERP_KERNEL::Node(coo1[2*nodeId],coo1[2*nodeId+1]);
4450 * Construct a mapping between set of Nodes and the standart MEDCoupling connectivity format (c, cI).
4452 void MEDCouplingUMeshBuildQPFromMesh3(const double *coo1, int offset1, const double *coo2, int offset2, const std::vector<double>& addCoo,
4453 const int *desc1Bg, const int *desc1End, const std::vector<std::vector<int> >& intesctEdges1,
4454 /*output*/std::map<INTERP_KERNEL::Node *,int>& mapp, std::map<int,INTERP_KERNEL::Node *>& mappRev)
4456 for(const int *desc1=desc1Bg;desc1!=desc1End;desc1++)
4458 int eltId1=abs(*desc1)-1;
4459 for(std::vector<int>::const_iterator it1=intesctEdges1[eltId1].begin();it1!=intesctEdges1[eltId1].end();it1++)
4461 std::map<int,INTERP_KERNEL::Node *>::const_iterator it=mappRev.find(*it1);
4462 if(it==mappRev.end())
4464 INTERP_KERNEL::Node *node=MEDCouplingUMeshBuildQPNode(*it1,coo1,offset1,coo2,offset2,addCoo);
4475 template<int SPACEDIM>
4476 void MEDCouplingUMesh::getCellsContainingPointsAlg(const double *coords, const double *pos, int nbOfPoints,
4477 double eps, MCAuto<DataArrayInt>& elts, MCAuto<DataArrayInt>& eltsIndex) const
4479 elts=DataArrayInt::New(); eltsIndex=DataArrayInt::New(); eltsIndex->alloc(nbOfPoints+1,1); eltsIndex->setIJ(0,0,0); elts->alloc(0,1);
4480 int *eltsIndexPtr(eltsIndex->getPointer());
4481 MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree(eps));
4482 const double *bbox(bboxArr->begin());
4483 int nbOfCells=getNumberOfCells();
4484 const int *conn=_nodal_connec->getConstPointer();
4485 const int *connI=_nodal_connec_index->getConstPointer();
4486 double bb[2*SPACEDIM];
4487 BBTree<SPACEDIM,int> myTree(&bbox[0],0,0,nbOfCells,-eps);
4488 for(int i=0;i<nbOfPoints;i++)
4490 eltsIndexPtr[i+1]=eltsIndexPtr[i];
4491 for(int j=0;j<SPACEDIM;j++)
4493 bb[2*j]=pos[SPACEDIM*i+j];
4494 bb[2*j+1]=pos[SPACEDIM*i+j];
4496 std::vector<int> candidates;
4497 myTree.getIntersectingElems(bb,candidates);
4498 for(std::vector<int>::const_iterator iter=candidates.begin();iter!=candidates.end();iter++)
4500 int sz(connI[(*iter)+1]-connI[*iter]-1);
4501 INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[connI[*iter]]);
4503 if(ct!=INTERP_KERNEL::NORM_POLYGON && ct!=INTERP_KERNEL::NORM_QPOLYG)
4504 status=INTERP_KERNEL::PointLocatorAlgos<DummyClsMCUG<SPACEDIM> >::isElementContainsPoint(pos+i*SPACEDIM,ct,coords,conn+connI[*iter]+1,sz,eps);
4508 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPointsAlg : not implemented yet for POLYGON and QPOLYGON in spaceDim 3 !");
4509 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
4510 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
4511 std::vector<INTERP_KERNEL::Node *> nodes(sz);
4512 INTERP_KERNEL::QuadraticPolygon *pol(0);
4513 for(int j=0;j<sz;j++)
4515 int nodeId(conn[connI[*iter]+1+j]);
4516 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*SPACEDIM],coords[nodeId*SPACEDIM+1]);
4518 if(!INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic())
4519 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
4521 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
4522 INTERP_KERNEL::Node *n(new INTERP_KERNEL::Node(pos[i*SPACEDIM],pos[i*SPACEDIM+1]));
4523 double a(0.),b(0.),c(0.);
4524 a=pol->normalizeMe(b,c); n->applySimilarity(b,c,a);
4525 status=pol->isInOrOut2(n);
4526 delete pol; n->decrRef();
4530 eltsIndexPtr[i+1]++;
4531 elts->pushBackSilent(*iter);
4537 * Finds cells in contact with several balls (i.e. points with precision).
4538 * This method is an extension of getCellContainingPoint() and
4539 * getCellsContainingPoint() for the case of multiple points.
4540 * 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.
4541 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4542 * \param [in] pos - an array of coordinates of points in full interlace mode :
4543 * X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4544 * this->getSpaceDimension() * \a nbOfPoints
4545 * \param [in] nbOfPoints - number of points to locate within \a this mesh.
4546 * \param [in] eps - radius of balls (i.e. the precision).
4547 * \param [out] elts - vector returning ids of found cells.
4548 * \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4549 * dividing cell ids in \a elts into groups each referring to one
4550 * point. Its every element (except the last one) is an index pointing to the
4551 * first id of a group of cells. For example cells in contact with the *i*-th
4552 * point are described by following range of indices:
4553 * [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4554 * \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4555 * Number of cells in contact with the *i*-th point is
4556 * \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4557 * \throw If the coordinates array is not set.
4558 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4560 * \if ENABLE_EXAMPLES
4561 * \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4562 * \ref py_mcumesh_getCellsContainingPoints "Here is a Python example".
4565 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, int nbOfPoints, double eps,
4566 MCAuto<DataArrayInt>& elts, MCAuto<DataArrayInt>& eltsIndex) const
4568 int spaceDim=getSpaceDimension();
4569 int mDim=getMeshDimension();
4574 const double *coords=_coords->getConstPointer();
4575 getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4582 throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4584 else if(spaceDim==2)
4588 const double *coords=_coords->getConstPointer();
4589 getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4592 throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4594 else if(spaceDim==1)
4598 const double *coords=_coords->getConstPointer();
4599 getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4602 throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4605 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4609 * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4610 * least two its edges intersect each other anywhere except their extremities. An
4611 * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4612 * \param [in,out] cells - a vector returning ids of the found cells. It is not
4613 * cleared before filling in.
4614 * \param [in] eps - precision.
4615 * \throw If \a this->getMeshDimension() != 2.
4616 * \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4618 void MEDCouplingUMesh::checkButterflyCells(std::vector<int>& cells, double eps) const
4620 const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4621 if(getMeshDimension()!=2)
4622 throw INTERP_KERNEL::Exception(msg);
4623 int spaceDim=getSpaceDimension();
4624 if(spaceDim!=2 && spaceDim!=3)
4625 throw INTERP_KERNEL::Exception(msg);
4626 const int *conn=_nodal_connec->getConstPointer();
4627 const int *connI=_nodal_connec_index->getConstPointer();
4628 int nbOfCells=getNumberOfCells();
4629 std::vector<double> cell2DinS2;
4630 for(int i=0;i<nbOfCells;i++)
4632 int offset=connI[i];
4633 int nbOfNodesForCell=connI[i+1]-offset-1;
4634 if(nbOfNodesForCell<=3)
4636 bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4637 project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4638 if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4645 * This method is typically requested to unbutterfly 2D linear cells in \b this.
4647 * 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.
4648 * 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.
4650 * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4651 * This convex envelop is computed using Jarvis march algorithm.
4652 * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4653 * 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)
4654 * 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.
4656 * \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.
4657 * \sa MEDCouplingUMesh::colinearize2D
4659 DataArrayInt *MEDCouplingUMesh::convexEnvelop2D()
4661 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4662 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D works only for meshDim=2 and spaceDim=2 !");
4663 checkFullyDefined();
4664 const double *coords=getCoords()->getConstPointer();
4665 int nbOfCells=getNumberOfCells();
4666 MCAuto<DataArrayInt> nodalConnecIndexOut=DataArrayInt::New();
4667 nodalConnecIndexOut->alloc(nbOfCells+1,1);
4668 MCAuto<DataArrayInt> nodalConnecOut(DataArrayInt::New());
4669 int *workIndexOut=nodalConnecIndexOut->getPointer();
4671 const int *nodalConnecIn=_nodal_connec->getConstPointer();
4672 const int *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4673 std::set<INTERP_KERNEL::NormalizedCellType> types;
4674 MCAuto<DataArrayInt> isChanged(DataArrayInt::New());
4675 isChanged->alloc(0,1);
4676 for(int i=0;i<nbOfCells;i++,workIndexOut++)
4678 int pos=nodalConnecOut->getNumberOfTuples();
4679 if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4680 isChanged->pushBackSilent(i);
4681 types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4682 workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4684 if(isChanged->empty())
4686 setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4688 return isChanged.retn();
4692 * This method is \b NOT const because it can modify \a this.
4693 * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4694 * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4695 * \param policy specifies the type of extrusion chosen:
4696 * - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4697 * will be repeated to build each level
4698 * - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4699 * 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
4700 * 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
4702 * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4704 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4706 checkFullyDefined();
4707 mesh1D->checkFullyDefined();
4708 if(!mesh1D->isContiguous1D())
4709 throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4710 if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4711 throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4712 if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4713 throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4714 if(mesh1D->getMeshDimension()!=1)
4715 throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4717 if(isPresenceOfQuadratic())
4719 if(mesh1D->isFullyQuadratic())
4722 throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4724 int oldNbOfNodes(getNumberOfNodes());
4725 MCAuto<DataArrayDouble> newCoords;
4730 newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4735 newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4739 throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4741 setCoords(newCoords);
4742 MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4748 * This method works on a 3D curve linear mesh that is to say (meshDim==1 and spaceDim==3).
4749 * If it is not the case an exception will be thrown.
4750 * This method is non const because the coordinate of \a this can be appended with some new points issued from
4751 * intersection of plane defined by ('origin','vec').
4752 * This method has one in/out parameter : 'cut3DCurve'.
4753 * Param 'cut3DCurve' is expected to be of size 'this->getNumberOfCells()'. For each i in [0,'this->getNumberOfCells()')
4754 * if cut3DCurve[i]==-2, it means that for cell #i in \a this nothing has been detected previously.
4755 * if cut3DCurve[i]==-1, it means that cell#i has been already detected to be fully part of plane defined by ('origin','vec').
4756 * This method will throw an exception if \a this contains a non linear segment.
4758 void MEDCouplingUMesh::split3DCurveWithPlane(const double *origin, const double *vec, double eps, std::vector<int>& cut3DCurve)
4760 checkFullyDefined();
4761 if(getMeshDimension()!=1 || getSpaceDimension()!=3)
4762 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane works on umeshes with meshdim equal to 1 and spaceDim equal to 3 !");
4763 int ncells=getNumberOfCells();
4764 int nnodes=getNumberOfNodes();
4765 double vec2[3],vec3[3],vec4[3];
4766 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
4768 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
4769 vec2[0]=vec[0]/normm; vec2[1]=vec[1]/normm; vec2[2]=vec[2]/normm;
4770 const int *conn=_nodal_connec->getConstPointer();
4771 const int *connI=_nodal_connec_index->getConstPointer();
4772 const double *coo=_coords->getConstPointer();
4773 std::vector<double> addCoo;
4774 for(int i=0;i<ncells;i++)
4776 if(conn[connI[i]]==(int)INTERP_KERNEL::NORM_SEG2)
4778 if(cut3DCurve[i]==-2)
4780 int st=conn[connI[i]+1],endd=conn[connI[i]+2];
4781 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];
4782 double normm2=sqrt(vec3[0]*vec3[0]+vec3[1]*vec3[1]+vec3[2]*vec3[2]);
4783 double colin=std::abs((vec3[0]*vec2[0]+vec3[1]*vec2[1]+vec3[2]*vec2[2])/normm2);
4784 if(colin>eps)//if colin<=eps -> current SEG2 is colinear to the input plane
4786 const double *st2=coo+3*st;
4787 vec4[0]=st2[0]-origin[0]; vec4[1]=st2[1]-origin[1]; vec4[2]=st2[2]-origin[2];
4788 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]));
4789 if(pos>eps && pos<1-eps)
4791 int nNode=((int)addCoo.size())/3;
4792 vec4[0]=st2[0]+pos*vec3[0]; vec4[1]=st2[1]+pos*vec3[1]; vec4[2]=st2[2]+pos*vec3[2];
4793 addCoo.insert(addCoo.end(),vec4,vec4+3);
4794 cut3DCurve[i]=nnodes+nNode;
4800 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane : this method is only available for linear cell (NORM_SEG2) !");
4804 int newNbOfNodes=nnodes+((int)addCoo.size())/3;
4805 MCAuto<DataArrayDouble> coo2=DataArrayDouble::New();
4806 coo2->alloc(newNbOfNodes,3);
4807 double *tmp=coo2->getPointer();
4808 tmp=std::copy(_coords->begin(),_coords->end(),tmp);
4809 std::copy(addCoo.begin(),addCoo.end(),tmp);
4810 DataArrayDouble::SetArrayIn(coo2,_coords);
4815 * This method incarnates the policy 0 for MEDCouplingUMesh::buildExtrudedMesh method.
4816 * \param mesh1D is the input 1D mesh used for translation computation.
4817 * \return newCoords new coords filled by this method.
4819 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslation(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4821 int oldNbOfNodes=getNumberOfNodes();
4822 int nbOf1DCells=mesh1D->getNumberOfCells();
4823 int spaceDim=getSpaceDimension();
4824 DataArrayDouble *ret=DataArrayDouble::New();
4825 std::vector<bool> isQuads;
4826 int nbOfLevsInVec=isQuad?2*nbOf1DCells+1:nbOf1DCells+1;
4827 ret->alloc(oldNbOfNodes*nbOfLevsInVec,spaceDim);
4828 double *retPtr=ret->getPointer();
4829 const double *coords=getCoords()->getConstPointer();
4830 double *work=std::copy(coords,coords+spaceDim*oldNbOfNodes,retPtr);
4832 std::vector<double> c;
4836 for(int i=0;i<nbOf1DCells;i++)
4839 mesh1D->getNodeIdsOfCell(i,v);
4841 mesh1D->getCoordinatesOfNode(v[isQuad?2:1],c);
4842 mesh1D->getCoordinatesOfNode(v[0],c);
4843 std::transform(c.begin(),c.begin()+spaceDim,c.begin()+spaceDim,vec,std::minus<double>());
4844 for(int j=0;j<oldNbOfNodes;j++)
4845 work=std::transform(vec,vec+spaceDim,retPtr+spaceDim*(i*oldNbOfNodes+j),work,std::plus<double>());
4849 mesh1D->getCoordinatesOfNode(v[1],c);
4850 mesh1D->getCoordinatesOfNode(v[0],c);
4851 std::transform(c.begin(),c.begin()+spaceDim,c.begin()+spaceDim,vec,std::minus<double>());
4852 for(int j=0;j<oldNbOfNodes;j++)
4853 work=std::transform(vec,vec+spaceDim,retPtr+spaceDim*(i*oldNbOfNodes+j),work,std::plus<double>());
4856 ret->copyStringInfoFrom(*getCoords());
4861 * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4862 * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4863 * \return newCoords new coords filled by this method.
4865 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4867 if(mesh1D->getSpaceDimension()==2)
4868 return fillExtCoordsUsingTranslAndAutoRotation2D(mesh1D,isQuad);
4869 if(mesh1D->getSpaceDimension()==3)
4870 return fillExtCoordsUsingTranslAndAutoRotation3D(mesh1D,isQuad);
4871 throw INTERP_KERNEL::Exception("Not implemented rotation and translation alg. for spacedim other than 2 and 3 !");
4875 * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4876 * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4877 * \return newCoords new coords filled by this method.
4879 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4882 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D : not implemented for quadratic cells !");
4883 int oldNbOfNodes=getNumberOfNodes();
4884 int nbOf1DCells=mesh1D->getNumberOfCells();
4886 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D : impossible to detect any angle of rotation ! Change extrusion policy 1->0 !");
4887 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
4888 int nbOfLevsInVec=nbOf1DCells+1;
4889 ret->alloc(oldNbOfNodes*nbOfLevsInVec,2);
4890 double *retPtr=ret->getPointer();
4891 retPtr=std::copy(getCoords()->getConstPointer(),getCoords()->getConstPointer()+getCoords()->getNbOfElems(),retPtr);
4892 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
4893 MCAuto<DataArrayDouble> tmp2=getCoords()->deepCopy();
4894 tmp->setCoords(tmp2);
4895 const double *coo1D=mesh1D->getCoords()->getConstPointer();
4896 const int *conn1D=mesh1D->getNodalConnectivity()->getConstPointer();
4897 const int *connI1D=mesh1D->getNodalConnectivityIndex()->getConstPointer();
4898 for(int i=1;i<nbOfLevsInVec;i++)
4900 const double *begin=coo1D+2*conn1D[connI1D[i-1]+1];
4901 const double *end=coo1D+2*conn1D[connI1D[i-1]+2];
4902 const double *third=i+1<nbOfLevsInVec?coo1D+2*conn1D[connI1D[i]+2]:coo1D+2*conn1D[connI1D[i-2]+1];
4903 const double vec[2]={end[0]-begin[0],end[1]-begin[1]};
4904 tmp->translate(vec);
4905 double tmp3[2],radius,alpha,alpha0;
4906 const double *p0=i+1<nbOfLevsInVec?begin:third;
4907 const double *p1=i+1<nbOfLevsInVec?end:begin;
4908 const double *p2=i+1<nbOfLevsInVec?third:end;
4909 INTERP_KERNEL::EdgeArcCircle::GetArcOfCirclePassingThru(p0,p1,p2,tmp3,radius,alpha,alpha0);
4910 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]);
4911 double angle=acos(cosangle/(radius*radius));
4912 tmp->rotate(end,0,angle);
4913 retPtr=std::copy(tmp2->getConstPointer(),tmp2->getConstPointer()+tmp2->getNbOfElems(),retPtr);
4919 * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4920 * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4921 * \return newCoords new coords filled by this method.
4923 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4926 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D : not implemented for quadratic cells !");
4927 int oldNbOfNodes=getNumberOfNodes();
4928 int nbOf1DCells=mesh1D->getNumberOfCells();
4930 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D : impossible to detect any angle of rotation ! Change extrusion policy 1->0 !");
4931 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
4932 int nbOfLevsInVec=nbOf1DCells+1;
4933 ret->alloc(oldNbOfNodes*nbOfLevsInVec,3);
4934 double *retPtr=ret->getPointer();
4935 retPtr=std::copy(getCoords()->getConstPointer(),getCoords()->getConstPointer()+getCoords()->getNbOfElems(),retPtr);
4936 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
4937 MCAuto<DataArrayDouble> tmp2=getCoords()->deepCopy();
4938 tmp->setCoords(tmp2);
4939 const double *coo1D=mesh1D->getCoords()->getConstPointer();
4940 const int *conn1D=mesh1D->getNodalConnectivity()->getConstPointer();
4941 const int *connI1D=mesh1D->getNodalConnectivityIndex()->getConstPointer();
4942 for(int i=1;i<nbOfLevsInVec;i++)
4944 const double *begin=coo1D+3*conn1D[connI1D[i-1]+1];
4945 const double *end=coo1D+3*conn1D[connI1D[i-1]+2];
4946 const double *third=i+1<nbOfLevsInVec?coo1D+3*conn1D[connI1D[i]+2]:coo1D+3*conn1D[connI1D[i-2]+1];
4947 const double vec[3]={end[0]-begin[0],end[1]-begin[1],end[2]-begin[2]};
4948 tmp->translate(vec);
4949 double tmp3[2],radius,alpha,alpha0;
4950 const double *p0=i+1<nbOfLevsInVec?begin:third;
4951 const double *p1=i+1<nbOfLevsInVec?end:begin;
4952 const double *p2=i+1<nbOfLevsInVec?third:end;
4953 double vecPlane[3]={
4954 (p1[1]-p0[1])*(p2[2]-p1[2])-(p1[2]-p0[2])*(p2[1]-p1[1]),
4955 (p1[2]-p0[2])*(p2[0]-p1[0])-(p1[0]-p0[0])*(p2[2]-p1[2]),
4956 (p1[0]-p0[0])*(p2[1]-p1[1])-(p1[1]-p0[1])*(p2[0]-p1[0]),
4958 double norm=sqrt(vecPlane[0]*vecPlane[0]+vecPlane[1]*vecPlane[1]+vecPlane[2]*vecPlane[2]);
4961 vecPlane[0]/=norm; vecPlane[1]/=norm; vecPlane[2]/=norm;
4962 double norm2=sqrt(vecPlane[0]*vecPlane[0]+vecPlane[1]*vecPlane[1]);
4963 double vec2[2]={vecPlane[1]/norm2,-vecPlane[0]/norm2};
4965 double c2=cos(asin(s2));
4967 {vec2[0]*vec2[0]*(1-c2)+c2, vec2[0]*vec2[1]*(1-c2), vec2[1]*s2},
4968 {vec2[0]*vec2[1]*(1-c2), vec2[1]*vec2[1]*(1-c2)+c2, -vec2[0]*s2},
4969 {-vec2[1]*s2, vec2[0]*s2, c2}
4971 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]};
4972 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]};
4973 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]};
4974 INTERP_KERNEL::EdgeArcCircle::GetArcOfCirclePassingThru(p0r,p1r,p2r,tmp3,radius,alpha,alpha0);
4975 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]);
4976 double angle=acos(cosangle/(radius*radius));
4977 tmp->rotate(end,vecPlane,angle);
4979 retPtr=std::copy(tmp2->getConstPointer(),tmp2->getConstPointer()+tmp2->getNbOfElems(),retPtr);
4985 * This method is private because not easy to use for end user. This method is const contrary to
4986 * MEDCouplingUMesh::buildExtrudedMesh method because this->_coords are expected to contain
4987 * the coords sorted slice by slice.
4988 * \param isQuad specifies presence of quadratic cells.
4990 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMeshFromThisLowLev(int nbOfNodesOf1Lev, bool isQuad) const
4992 int nbOf1DCells(getNumberOfNodes()/nbOfNodesOf1Lev-1);
4993 int nbOf2DCells(getNumberOfCells());
4994 int nbOf3DCells(nbOf2DCells*nbOf1DCells);
4995 MEDCouplingUMesh *ret(MEDCouplingUMesh::New("Extruded",getMeshDimension()+1));
4996 const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
4997 MCAuto<DataArrayInt> newConn(DataArrayInt::New()),newConnI(DataArrayInt::New());
4998 newConnI->alloc(nbOf3DCells+1,1);
4999 int *newConnIPtr(newConnI->getPointer());
5001 std::vector<int> newc;
5002 for(int j=0;j<nbOf2DCells;j++)
5004 AppendExtrudedCell(conn+connI[j],conn+connI[j+1],nbOfNodesOf1Lev,isQuad,newc);
5005 *newConnIPtr++=(int)newc.size();
5007 newConn->alloc((int)(newc.size())*nbOf1DCells,1);
5008 int *newConnPtr(newConn->getPointer());
5009 int deltaPerLev(isQuad?2*nbOfNodesOf1Lev:nbOfNodesOf1Lev);
5010 newConnIPtr=newConnI->getPointer();
5011 for(int iz=0;iz<nbOf1DCells;iz++)
5014 std::transform(newConnIPtr+1,newConnIPtr+1+nbOf2DCells,newConnIPtr+1+iz*nbOf2DCells,std::bind2nd(std::plus<int>(),newConnIPtr[iz*nbOf2DCells]));
5015 const int *posOfTypeOfCell(newConnIPtr);
5016 for(std::vector<int>::const_iterator iter=newc.begin();iter!=newc.end();iter++,newConnPtr++)
5018 int icell((int)(iter-newc.begin()));//std::distance unfortunately cannot been called here in C++98
5019 if(icell!=*posOfTypeOfCell)
5022 *newConnPtr=(*iter)+iz*deltaPerLev;
5033 ret->setConnectivity(newConn,newConnI,true);
5034 ret->setCoords(getCoords());
5039 * Checks if \a this mesh is constituted by only quadratic cells.
5040 * \return bool - \c true if there are only quadratic cells in \a this mesh.
5041 * \throw If the coordinates array is not set.
5042 * \throw If the nodal connectivity of cells is not defined.
5044 bool MEDCouplingUMesh::isFullyQuadratic() const
5046 checkFullyDefined();
5048 int nbOfCells=getNumberOfCells();
5049 for(int i=0;i<nbOfCells && ret;i++)
5051 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5052 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5053 ret=cm.isQuadratic();
5059 * Checks if \a this mesh includes any quadratic cell.
5060 * \return bool - \c true if there is at least one quadratic cells in \a this mesh.
5061 * \throw If the coordinates array is not set.
5062 * \throw If the nodal connectivity of cells is not defined.
5064 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
5066 checkFullyDefined();
5068 int nbOfCells=getNumberOfCells();
5069 for(int i=0;i<nbOfCells && !ret;i++)
5071 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5072 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5073 ret=cm.isQuadratic();
5079 * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
5080 * this mesh, it remains unchanged.
5081 * \throw If the coordinates array is not set.
5082 * \throw If the nodal connectivity of cells is not defined.
5084 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
5086 checkFullyDefined();
5087 int nbOfCells=getNumberOfCells();
5089 const int *iciptr=_nodal_connec_index->getConstPointer();
5090 for(int i=0;i<nbOfCells;i++)
5092 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5093 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5094 if(cm.isQuadratic())
5096 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
5097 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
5098 if(!cml.isDynamic())
5099 delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
5101 delta+=(iciptr[i+1]-iciptr[i]-1)/2;
5106 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5107 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5108 const int *icptr=_nodal_connec->getConstPointer();
5109 newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
5110 newConnI->alloc(nbOfCells+1,1);
5111 int *ocptr=newConn->getPointer();
5112 int *ociptr=newConnI->getPointer();
5115 for(int i=0;i<nbOfCells;i++,ociptr++)
5117 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
5118 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5119 if(!cm.isQuadratic())
5121 _types.insert(type);
5122 ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
5123 ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
5127 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
5128 _types.insert(typel);
5129 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
5130 int newNbOfNodes=cml.getNumberOfNodes();
5132 newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
5133 *ocptr++=(int)typel;
5134 ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
5135 ociptr[1]=ociptr[0]+newNbOfNodes+1;
5138 setConnectivity(newConn,newConnI,false);
5142 * This method converts all linear cell in \a this to quadratic one.
5143 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
5144 * 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)
5145 * 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.
5146 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
5147 * end of the existing coordinates.
5149 * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
5150 * corresponding quadratic cells. 1 is those creating the 'most' complex.
5151 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5153 * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
5155 * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
5157 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
5159 DataArrayInt *conn=0,*connI=0;
5160 DataArrayDouble *coords=0;
5161 std::set<INTERP_KERNEL::NormalizedCellType> types;
5162 checkFullyDefined();
5163 MCAuto<DataArrayInt> ret,connSafe,connISafe;
5164 MCAuto<DataArrayDouble> coordsSafe;
5165 int meshDim=getMeshDimension();
5166 switch(conversionType)
5172 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
5173 connSafe=conn; connISafe=connI; coordsSafe=coords;
5176 ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
5177 connSafe=conn; connISafe=connI; coordsSafe=coords;
5180 ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
5181 connSafe=conn; connISafe=connI; coordsSafe=coords;
5184 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
5192 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
5193 connSafe=conn; connISafe=connI; coordsSafe=coords;
5196 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
5197 connSafe=conn; connISafe=connI; coordsSafe=coords;
5200 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
5201 connSafe=conn; connISafe=connI; coordsSafe=coords;
5204 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
5209 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
5211 setConnectivity(connSafe,connISafe,false);
5213 setCoords(coordsSafe);
5218 * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
5219 * so that the number of cells remains the same. Quadratic faces are converted to
5220 * polygons. This method works only for 2D meshes in
5221 * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
5222 * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
5223 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5224 * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
5225 * a polylinized edge constituting the input polygon.
5226 * \throw If the coordinates array is not set.
5227 * \throw If the nodal connectivity of cells is not defined.
5228 * \throw If \a this->getMeshDimension() != 2.
5229 * \throw If \a this->getSpaceDimension() != 2.
5231 void MEDCouplingUMesh::tessellate2D(double eps)
5233 int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
5235 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
5239 return tessellate2DCurveInternal(eps);
5241 return tessellate2DInternal(eps);
5243 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
5247 * Tessellates \a this 1D mesh in 2D space by dividing not straight quadratic edges.
5248 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5249 * \param [in] eps - specifies the maximal angle (in radian) between 2 sub-edges of
5250 * a sub-divided edge.
5251 * \throw If the coordinates array is not set.
5252 * \throw If the nodal connectivity of cells is not defined.
5253 * \throw If \a this->getMeshDimension() != 1.
5254 * \throw If \a this->getSpaceDimension() != 2.
5259 * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
5260 * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
5261 * The nodes to be added in those 2D cells are defined by the pair of \a nodeIdsToAdd and \a nodeIdsIndexToAdd.
5262 * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
5263 * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
5264 * This method can be seen as the opposite method of colinearize2D.
5265 * 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
5266 * to avoid to modify the numbering of existing nodes.
5268 * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
5269 * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
5270 * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
5271 * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
5272 * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
5273 * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
5274 * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
5276 * \sa buildDescendingConnectivity2
5278 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayInt *nodeIdsToAdd, const DataArrayInt *nodeIdsIndexToAdd, const DataArrayInt *edgeIdsToBeSplit,
5279 const MEDCouplingUMesh *mesh1Desc, const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *revDesc, const DataArrayInt *revDescI)
5281 if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
5282 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
5283 nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
5284 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
5285 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
5286 if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
5287 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
5288 //DataArrayInt *out0(0),*outi0(0);
5289 //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
5290 //MCAuto<DataArrayInt> out0s(out0),outi0s(outi0);
5291 //out0s=out0s->buildUnique(); out0s->sort(true);
5296 * Implementes \a conversionType 0 for meshes with meshDim = 1, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5297 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5298 * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5300 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic1D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5302 MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5303 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5304 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5305 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5306 int nbOfCells=getNumberOfCells();
5307 int nbOfNodes=getNumberOfNodes();
5308 const int *cPtr=_nodal_connec->getConstPointer();
5309 const int *icPtr=_nodal_connec_index->getConstPointer();
5310 int lastVal=0,offset=nbOfNodes;
5311 for(int i=0;i<nbOfCells;i++,icPtr++)
5313 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5314 if(type==INTERP_KERNEL::NORM_SEG2)
5316 types.insert(INTERP_KERNEL::NORM_SEG3);
5317 newConn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG3);
5318 newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[0]+3);
5319 newConn->pushBackSilent(offset++);
5321 newConnI->pushBackSilent(lastVal);
5322 ret->pushBackSilent(i);
5327 lastVal+=(icPtr[1]-icPtr[0]);
5328 newConnI->pushBackSilent(lastVal);
5329 newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5332 MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5333 coords=DataArrayDouble::Aggregate(getCoords(),tmp); conn=newConn.retn(); connI=newConnI.retn();
5337 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
5339 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5340 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5341 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5343 const int *descPtr(desc->begin()),*descIPtr(descI->begin());
5344 DataArrayInt *conn1D=0,*conn1DI=0;
5345 std::set<INTERP_KERNEL::NormalizedCellType> types1D;
5346 DataArrayDouble *coordsTmp=0;
5347 MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=0;
5348 MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5349 MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5350 const int *c1DPtr=conn1D->begin();
5351 const int *c1DIPtr=conn1DI->begin();
5352 int nbOfCells=getNumberOfCells();
5353 const int *cPtr=_nodal_connec->getConstPointer();
5354 const int *icPtr=_nodal_connec_index->getConstPointer();
5356 for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++)
5358 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5359 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5360 if(!cm.isQuadratic())
5362 INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType();
5363 types.insert(typ2); newConn->pushBackSilent(typ2);
5364 newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5365 for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5366 newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5367 lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0]);
5368 newConnI->pushBackSilent(lastVal);
5369 ret->pushBackSilent(i);
5374 lastVal+=(icPtr[1]-icPtr[0]);
5375 newConnI->pushBackSilent(lastVal);
5376 newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5379 conn=newConn.retn(); connI=newConnI.retn(); coords=coordsTmpSafe.retn();
5384 * Implementes \a conversionType 0 for meshes with meshDim = 2, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5385 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5386 * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5388 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic2D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5390 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5391 MCAuto<MEDCouplingUMesh> m1D=buildDescendingConnectivity(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5392 return convertLinearCellsToQuadratic2DAnd3D0(m1D,desc,descI,conn,connI,coords,types);
5395 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic2D1(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5397 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5398 MCAuto<MEDCouplingUMesh> m1D=buildDescendingConnectivity(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5400 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5401 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5402 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5404 MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5405 const int *descPtr(desc->begin()),*descIPtr(descI->begin());
5406 DataArrayInt *conn1D=0,*conn1DI=0;
5407 std::set<INTERP_KERNEL::NormalizedCellType> types1D;
5408 DataArrayDouble *coordsTmp=0;
5409 MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=0;
5410 MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5411 MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5412 const int *c1DPtr=conn1D->begin();
5413 const int *c1DIPtr=conn1DI->begin();
5414 int nbOfCells=getNumberOfCells();
5415 const int *cPtr=_nodal_connec->getConstPointer();
5416 const int *icPtr=_nodal_connec_index->getConstPointer();
5417 int lastVal=0,offset=coordsTmpSafe->getNumberOfTuples();
5418 for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++)
5420 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5421 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5422 if(!cm.isQuadratic())
5424 INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType2();
5425 types.insert(typ2); newConn->pushBackSilent(typ2);
5426 newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5427 for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5428 newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5429 newConn->pushBackSilent(offset+ret->getNumberOfTuples());
5430 lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0])+1;
5431 newConnI->pushBackSilent(lastVal);
5432 ret->pushBackSilent(i);
5437 lastVal+=(icPtr[1]-icPtr[0]);
5438 newConnI->pushBackSilent(lastVal);
5439 newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5442 MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5443 coords=DataArrayDouble::Aggregate(coordsTmpSafe,tmp); conn=newConn.retn(); connI=newConnI.retn();
5448 * Implementes \a conversionType 0 for meshes with meshDim = 3, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5449 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5450 * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5452 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic3D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5454 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5455 MCAuto<MEDCouplingUMesh> m1D=explode3DMeshTo1D(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5456 return convertLinearCellsToQuadratic2DAnd3D0(m1D,desc,descI,conn,connI,coords,types);
5459 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic3D1(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5461 MCAuto<DataArrayInt> desc2(DataArrayInt::New()),desc2I(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5462 MCAuto<MEDCouplingUMesh> m2D=buildDescendingConnectivityGen<MinusOneSonsGeneratorBiQuadratic>(desc2,desc2I,tmp2,tmp3,MEDCouplingFastNbrer); tmp2=0; tmp3=0;
5463 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),desc1I(DataArrayInt::New()),tmp4(DataArrayInt::New()),tmp5(DataArrayInt::New());
5464 MCAuto<MEDCouplingUMesh> m1D=explode3DMeshTo1D(desc1,desc1I,tmp4,tmp5); tmp4=0; tmp5=0;
5466 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5467 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5468 MCAuto<DataArrayInt> ret=DataArrayInt::New(),ret2=DataArrayInt::New(); ret->alloc(0,1); ret2->alloc(0,1);
5470 MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5471 const int *descPtr(desc1->begin()),*descIPtr(desc1I->begin()),*desc2Ptr(desc2->begin()),*desc2IPtr(desc2I->begin());
5472 DataArrayInt *conn1D=0,*conn1DI=0,*conn2D=0,*conn2DI=0;
5473 std::set<INTERP_KERNEL::NormalizedCellType> types1D,types2D;
5474 DataArrayDouble *coordsTmp=0,*coordsTmp2=0;
5475 MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=DataArrayInt::New(); ret1D->alloc(0,1);
5476 MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5477 MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5478 MCAuto<DataArrayInt> ret2D=m2D->convertLinearCellsToQuadratic2D1(conn2D,conn2DI,coordsTmp2,types2D); ret2D=DataArrayInt::New(); ret2D->alloc(0,1);
5479 MCAuto<DataArrayDouble> coordsTmp2Safe(coordsTmp2);
5480 MCAuto<DataArrayInt> conn2DSafe(conn2D),conn2DISafe(conn2DI);
5481 const int *c1DPtr=conn1D->begin(),*c1DIPtr=conn1DI->begin(),*c2DPtr=conn2D->begin(),*c2DIPtr=conn2DI->begin();
5482 int nbOfCells=getNumberOfCells();
5483 const int *cPtr=_nodal_connec->getConstPointer();
5484 const int *icPtr=_nodal_connec_index->getConstPointer();
5485 int lastVal=0,offset=coordsTmpSafe->getNumberOfTuples();
5486 for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++,desc2IPtr++)
5488 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5489 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5490 if(!cm.isQuadratic())
5492 INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType2();
5493 if(typ2==INTERP_KERNEL::NORM_ERROR)
5495 std::ostringstream oss; oss << "MEDCouplingUMesh::convertLinearCellsToQuadratic3D1 : On cell #" << i << " the linear cell type does not support advanced quadratization !";
5496 throw INTERP_KERNEL::Exception(oss.str().c_str());
5498 types.insert(typ2); newConn->pushBackSilent(typ2);
5499 newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5500 for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5501 newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5502 for(const int *d=desc2Ptr+desc2IPtr[0];d!=desc2Ptr+desc2IPtr[1];d++)
5504 int nodeId2=c2DPtr[c2DIPtr[(*d)+1]-1];
5505 int tmpPos=newConn->getNumberOfTuples();
5506 newConn->pushBackSilent(nodeId2);
5507 ret2D->pushBackSilent(nodeId2); ret1D->pushBackSilent(tmpPos);
5509 newConn->pushBackSilent(offset+ret->getNumberOfTuples());
5510 lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0])+(desc2IPtr[1]-desc2IPtr[0])+1;
5511 newConnI->pushBackSilent(lastVal);
5512 ret->pushBackSilent(i);
5517 lastVal+=(icPtr[1]-icPtr[0]);
5518 newConnI->pushBackSilent(lastVal);
5519 newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5522 MCAuto<DataArrayInt> diffRet2D=ret2D->getDifferentValues();
5523 MCAuto<DataArrayInt> o2nRet2D=diffRet2D->invertArrayN2O2O2N(coordsTmp2Safe->getNumberOfTuples());
5524 coordsTmp2Safe=coordsTmp2Safe->selectByTupleId(diffRet2D->begin(),diffRet2D->end());
5525 MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5526 std::vector<const DataArrayDouble *> v(3); v[0]=coordsTmpSafe; v[1]=coordsTmp2Safe; v[2]=tmp;
5527 int *c=newConn->getPointer();
5528 const int *cI(newConnI->begin());
5529 for(const int *elt=ret1D->begin();elt!=ret1D->end();elt++)
5530 c[*elt]=o2nRet2D->getIJ(c[*elt],0)+offset;
5531 offset=coordsTmp2Safe->getNumberOfTuples();
5532 for(const int *elt=ret->begin();elt!=ret->end();elt++)
5533 c[cI[(*elt)+1]-1]+=offset;
5534 coords=DataArrayDouble::Aggregate(v); conn=newConn.retn(); connI=newConnI.retn();
5539 * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
5540 * In addition, returns an array mapping new cells to old ones. <br>
5541 * This method typically increases the number of cells in \a this mesh
5542 * but the number of nodes remains \b unchanged.
5543 * That's why the 3D splitting policies
5544 * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
5545 * \param [in] policy - specifies a pattern used for splitting.
5546 * The semantic of \a policy is:
5547 * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
5548 * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
5549 * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8 into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
5550 * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8 into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
5553 * \return DataArrayInt * - a new instance of DataArrayInt holding, for each new cell,
5554 * an id of old cell producing it. The caller is to delete this array using
5555 * decrRef() as it is no more needed.
5557 * \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
5558 * \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
5559 * and \a this->getMeshDimension() != 3.
5560 * \throw If \a policy is not one of the four discussed above.
5561 * \throw If the nodal connectivity of cells is not defined.
5562 * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
5564 DataArrayInt *MEDCouplingUMesh::simplexize(int policy)
5569 return simplexizePol0();
5571 return simplexizePol1();
5572 case (int) INTERP_KERNEL::PLANAR_FACE_5:
5573 return simplexizePlanarFace5();
5574 case (int) INTERP_KERNEL::PLANAR_FACE_6:
5575 return simplexizePlanarFace6();
5577 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)");
5582 * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
5583 * - 1D: INTERP_KERNEL::NORM_SEG2
5584 * - 2D: INTERP_KERNEL::NORM_TRI3
5585 * - 3D: INTERP_KERNEL::NORM_TETRA4.
5587 * This method is useful for users that need to use P1 field services as
5588 * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
5589 * All these methods need mesh support containing only simplex cells.
5590 * \return bool - \c true if there are only simplex cells in \a this mesh.
5591 * \throw If the coordinates array is not set.
5592 * \throw If the nodal connectivity of cells is not defined.
5593 * \throw If \a this->getMeshDimension() < 1.
5595 bool MEDCouplingUMesh::areOnlySimplexCells() const
5597 checkFullyDefined();
5598 int mdim=getMeshDimension();
5599 if(mdim<1 || mdim>3)
5600 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
5601 int nbCells=getNumberOfCells();
5602 const int *conn=_nodal_connec->getConstPointer();
5603 const int *connI=_nodal_connec_index->getConstPointer();
5604 for(int i=0;i<nbCells;i++)
5606 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5614 * This method implements policy 0 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5616 DataArrayInt *MEDCouplingUMesh::simplexizePol0()
5618 checkConnectivityFullyDefined();
5619 if(getMeshDimension()!=2)
5620 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePol0 : this policy is only available for mesh with meshdim == 2 !");
5621 int nbOfCells=getNumberOfCells();
5622 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5623 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_QUAD4);
5624 ret->alloc(nbOfCells+nbOfCutCells,1);
5625 if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5626 int *retPt=ret->getPointer();
5627 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5628 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5629 newConnI->alloc(nbOfCells+nbOfCutCells+1,1);
5630 newConn->alloc(getNodalConnectivityArrayLen()+3*nbOfCutCells,1);
5631 int *pt=newConn->getPointer();
5632 int *ptI=newConnI->getPointer();
5634 const int *oldc=_nodal_connec->getConstPointer();
5635 const int *ci=_nodal_connec_index->getConstPointer();
5636 for(int i=0;i<nbOfCells;i++,ci++)
5638 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_QUAD4)
5640 const int tmp[8]={(int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+2],oldc[ci[0]+3],
5641 (int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+3],oldc[ci[0]+4]};
5642 pt=std::copy(tmp,tmp+8,pt);
5651 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5652 ptI[1]=ptI[0]+ci[1]-ci[0];
5657 _nodal_connec->decrRef();
5658 _nodal_connec=newConn.retn();
5659 _nodal_connec_index->decrRef();
5660 _nodal_connec_index=newConnI.retn();
5667 * This method implements policy 1 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5669 DataArrayInt *MEDCouplingUMesh::simplexizePol1()
5671 checkConnectivityFullyDefined();
5672 if(getMeshDimension()!=2)
5673 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePol0 : this policy is only available for mesh with meshdim == 2 !");
5674 int nbOfCells=getNumberOfCells();
5675 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5676 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_QUAD4);
5677 ret->alloc(nbOfCells+nbOfCutCells,1);
5678 if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5679 int *retPt=ret->getPointer();
5680 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5681 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5682 newConnI->alloc(nbOfCells+nbOfCutCells+1,1);
5683 newConn->alloc(getNodalConnectivityArrayLen()+3*nbOfCutCells,1);
5684 int *pt=newConn->getPointer();
5685 int *ptI=newConnI->getPointer();
5687 const int *oldc=_nodal_connec->getConstPointer();
5688 const int *ci=_nodal_connec_index->getConstPointer();
5689 for(int i=0;i<nbOfCells;i++,ci++)
5691 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_QUAD4)
5693 const int tmp[8]={(int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+2],oldc[ci[0]+4],
5694 (int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+2],oldc[ci[0]+3],oldc[ci[0]+4]};
5695 pt=std::copy(tmp,tmp+8,pt);
5704 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5705 ptI[1]=ptI[0]+ci[1]-ci[0];
5710 _nodal_connec->decrRef();
5711 _nodal_connec=newConn.retn();
5712 _nodal_connec_index->decrRef();
5713 _nodal_connec_index=newConnI.retn();
5720 * This method implements policy INTERP_KERNEL::PLANAR_FACE_5 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5722 DataArrayInt *MEDCouplingUMesh::simplexizePlanarFace5()
5724 checkConnectivityFullyDefined();
5725 if(getMeshDimension()!=3)
5726 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePlanarFace5 : this policy is only available for mesh with meshdim == 3 !");
5727 int nbOfCells=getNumberOfCells();
5728 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5729 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_HEXA8);
5730 ret->alloc(nbOfCells+4*nbOfCutCells,1);
5731 if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5732 int *retPt=ret->getPointer();
5733 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5734 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5735 newConnI->alloc(nbOfCells+4*nbOfCutCells+1,1);
5736 newConn->alloc(getNodalConnectivityArrayLen()+16*nbOfCutCells,1);//21
5737 int *pt=newConn->getPointer();
5738 int *ptI=newConnI->getPointer();
5740 const int *oldc=_nodal_connec->getConstPointer();
5741 const int *ci=_nodal_connec_index->getConstPointer();
5742 for(int i=0;i<nbOfCells;i++,ci++)
5744 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_HEXA8)
5746 for(int j=0;j<5;j++,pt+=5,ptI++)
5748 pt[0]=(int)INTERP_KERNEL::NORM_TETRA4;
5749 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];
5756 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5757 ptI[1]=ptI[0]+ci[1]-ci[0];
5762 _nodal_connec->decrRef();
5763 _nodal_connec=newConn.retn();
5764 _nodal_connec_index->decrRef();
5765 _nodal_connec_index=newConnI.retn();
5772 * This method implements policy INTERP_KERNEL::PLANAR_FACE_6 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5774 DataArrayInt *MEDCouplingUMesh::simplexizePlanarFace6()
5776 checkConnectivityFullyDefined();
5777 if(getMeshDimension()!=3)
5778 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePlanarFace6 : this policy is only available for mesh with meshdim == 3 !");
5779 int nbOfCells=getNumberOfCells();
5780 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5781 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_HEXA8);
5782 ret->alloc(nbOfCells+5*nbOfCutCells,1);
5783 if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5784 int *retPt=ret->getPointer();
5785 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5786 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5787 newConnI->alloc(nbOfCells+5*nbOfCutCells+1,1);
5788 newConn->alloc(getNodalConnectivityArrayLen()+21*nbOfCutCells,1);
5789 int *pt=newConn->getPointer();
5790 int *ptI=newConnI->getPointer();
5792 const int *oldc=_nodal_connec->getConstPointer();
5793 const int *ci=_nodal_connec_index->getConstPointer();
5794 for(int i=0;i<nbOfCells;i++,ci++)
5796 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_HEXA8)
5798 for(int j=0;j<6;j++,pt+=5,ptI++)
5800 pt[0]=(int)INTERP_KERNEL::NORM_TETRA4;
5801 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];
5808 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5809 ptI[1]=ptI[0]+ci[1]-ci[0];
5814 _nodal_connec->decrRef();
5815 _nodal_connec=newConn.retn();
5816 _nodal_connec_index->decrRef();
5817 _nodal_connec_index=newConnI.retn();
5824 * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
5825 * so that the number of cells remains the same. Quadratic faces are converted to
5826 * polygons. This method works only for 2D meshes in
5827 * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
5828 * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
5829 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5830 * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
5831 * a polylinized edge constituting the input polygon.
5832 * \throw If the coordinates array is not set.
5833 * \throw If the nodal connectivity of cells is not defined.
5834 * \throw If \a this->getMeshDimension() != 2.
5835 * \throw If \a this->getSpaceDimension() != 2.
5837 void MEDCouplingUMesh::tessellate2DInternal(double eps)
5839 checkFullyDefined();
5840 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
5841 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DInternal works on umeshes with meshdim equal to 2 and spaceDim equal to 2 too!");
5842 double epsa=fabs(eps);
5843 if(epsa<std::numeric_limits<double>::min())
5844 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 !");
5845 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
5846 MCAuto<MEDCouplingUMesh> mDesc(buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1));
5847 revDesc1=0; revDescIndx1=0;
5848 mDesc->tessellate2D(eps);
5849 subDivide2DMesh(mDesc->_nodal_connec->getConstPointer(),mDesc->_nodal_connec_index->getConstPointer(),desc1->getConstPointer(),descIndx1->getConstPointer());
5850 setCoords(mDesc->getCoords());
5854 * Tessellates \a this 1D mesh in 2D space by dividing not straight quadratic edges.
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 radian) between 2 sub-edges of
5857 * a sub-divided edge.
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() != 1.
5861 * \throw If \a this->getSpaceDimension() != 2.
5863 void MEDCouplingUMesh::tessellate2DCurveInternal(double eps)
5865 checkFullyDefined();
5866 if(getMeshDimension()!=1 || getSpaceDimension()!=2)
5867 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DCurveInternal works on umeshes with meshdim equal to 1 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::tessellate2DCurveInternal : epsilon is null ! Please specify a higher epsilon. If too tiny it can lead to a huge amount of nodes and memory !");
5871 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=1.e-10;
5872 int nbCells=getNumberOfCells();
5873 int nbNodes=getNumberOfNodes();
5874 const int *conn=_nodal_connec->getConstPointer();
5875 const int *connI=_nodal_connec_index->getConstPointer();
5876 const double *coords=_coords->getConstPointer();
5877 std::vector<double> addCoo;
5878 std::vector<int> newConn;//no direct DataArrayInt because interface with Geometric2D
5879 MCAuto<DataArrayInt> newConnI(DataArrayInt::New());
5880 newConnI->alloc(nbCells+1,1);
5881 int *newConnIPtr=newConnI->getPointer();
5884 INTERP_KERNEL::Node *tmp2[3];
5885 std::set<INTERP_KERNEL::NormalizedCellType> types;
5886 for(int i=0;i<nbCells;i++,newConnIPtr++)
5888 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5889 if(cm.isQuadratic())
5890 {//assert(connI[i+1]-connI[i]-1==3)
5891 tmp1[0]=conn[connI[i]+1+0]; tmp1[1]=conn[connI[i]+1+1]; tmp1[2]=conn[connI[i]+1+2];
5892 tmp2[0]=new INTERP_KERNEL::Node(coords[2*tmp1[0]],coords[2*tmp1[0]+1]);
5893 tmp2[1]=new INTERP_KERNEL::Node(coords[2*tmp1[1]],coords[2*tmp1[1]+1]);
5894 tmp2[2]=new INTERP_KERNEL::Node(coords[2*tmp1[2]],coords[2*tmp1[2]+1]);
5895 INTERP_KERNEL::EdgeArcCircle *eac=INTERP_KERNEL::EdgeArcCircle::BuildFromNodes(tmp2[0],tmp2[2],tmp2[1]);
5898 eac->tesselate(tmp1,nbNodes,epsa,newConn,addCoo);
5899 types.insert((INTERP_KERNEL::NormalizedCellType)newConn[newConnIPtr[0]]);
5901 newConnIPtr[1]=(int)newConn.size();
5905 types.insert(INTERP_KERNEL::NORM_SEG2);
5906 newConn.push_back(INTERP_KERNEL::NORM_SEG2);
5907 newConn.insert(newConn.end(),conn+connI[i]+1,conn+connI[i]+3);
5908 newConnIPtr[1]=newConnIPtr[0]+3;
5913 types.insert((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5914 newConn.insert(newConn.end(),conn+connI[i],conn+connI[i+1]);
5915 newConnIPtr[1]=newConnIPtr[0]+3;
5918 if(addCoo.empty() && ((int)newConn.size())==_nodal_connec->getNumberOfTuples())//nothing happens during tessellation : no update needed
5921 DataArrayInt::SetArrayIn(newConnI,_nodal_connec_index);
5922 MCAuto<DataArrayInt> newConnArr=DataArrayInt::New();
5923 newConnArr->alloc((int)newConn.size(),1);
5924 std::copy(newConn.begin(),newConn.end(),newConnArr->getPointer());
5925 DataArrayInt::SetArrayIn(newConnArr,_nodal_connec);
5926 MCAuto<DataArrayDouble> newCoords=DataArrayDouble::New();
5927 newCoords->alloc(nbNodes+((int)addCoo.size())/2,2);
5928 double *work=std::copy(_coords->begin(),_coords->end(),newCoords->getPointer());
5929 std::copy(addCoo.begin(),addCoo.end(),work);
5930 DataArrayDouble::SetArrayIn(newCoords,_coords);
5935 * 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.
5936 * This method completly ignore coordinates.
5937 * \param nodeSubdived is the nodal connectivity of subdivision of edges
5938 * \param nodeIndxSubdived is the nodal connectivity index of subdivision of edges
5939 * \param desc is descending connectivity in format specified in MEDCouplingUMesh::buildDescendingConnectivity2
5940 * \param descIndex is descending connectivity index in format specified in MEDCouplingUMesh::buildDescendingConnectivity2
5942 void MEDCouplingUMesh::subDivide2DMesh(const int *nodeSubdived, const int *nodeIndxSubdived, const int *desc, const int *descIndex)
5944 checkFullyDefined();
5945 if(getMeshDimension()!=2)
5946 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::subDivide2DMesh : works only on umesh with meshdim==2 !");
5947 int nbOfCells=getNumberOfCells();
5948 int *connI=_nodal_connec_index->getPointer();
5950 for(int i=0;i<nbOfCells;i++,connI++)
5952 int offset=descIndex[i];
5953 int nbOfEdges=descIndex[i+1]-offset;
5955 bool ddirect=desc[offset+nbOfEdges-1]>0;
5956 int eedgeId=std::abs(desc[offset+nbOfEdges-1])-1;
5957 int ref=ddirect?nodeSubdived[nodeIndxSubdived[eedgeId+1]-1]:nodeSubdived[nodeIndxSubdived[eedgeId]+1];
5958 for(int j=0;j<nbOfEdges;j++)
5960 bool direct=desc[offset+j]>0;
5961 int edgeId=std::abs(desc[offset+j])-1;
5962 if(!INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodeSubdived[nodeIndxSubdived[edgeId]]).isQuadratic())
5964 int id1=nodeSubdived[nodeIndxSubdived[edgeId]+1];
5965 int id2=nodeSubdived[nodeIndxSubdived[edgeId+1]-1];
5966 int ref2=direct?id1:id2;
5969 int nbOfSubNodes=nodeIndxSubdived[edgeId+1]-nodeIndxSubdived[edgeId]-1;
5970 newConnLgth+=nbOfSubNodes-1;
5975 std::ostringstream oss; oss << "MEDCouplingUMesh::subDivide2DMesh : On polygon #" << i << " edgeid #" << j << " subedges mismatch : end subedge k!=start subedge k+1 !";
5976 throw INTERP_KERNEL::Exception(oss.str().c_str());
5981 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::subDivide2DMesh : this method only subdivides into linear edges !");
5984 newConnLgth++;//+1 is for cell type
5985 connI[1]=newConnLgth;
5988 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5989 newConn->alloc(newConnLgth,1);
5990 int *work=newConn->getPointer();
5991 for(int i=0;i<nbOfCells;i++)
5993 *work++=INTERP_KERNEL::NORM_POLYGON;
5994 int offset=descIndex[i];
5995 int nbOfEdges=descIndex[i+1]-offset;
5996 for(int j=0;j<nbOfEdges;j++)
5998 bool direct=desc[offset+j]>0;
5999 int edgeId=std::abs(desc[offset+j])-1;
6001 work=std::copy(nodeSubdived+nodeIndxSubdived[edgeId]+1,nodeSubdived+nodeIndxSubdived[edgeId+1]-1,work);
6004 int nbOfSubNodes=nodeIndxSubdived[edgeId+1]-nodeIndxSubdived[edgeId]-1;
6005 std::reverse_iterator<const int *> it(nodeSubdived+nodeIndxSubdived[edgeId+1]);
6006 work=std::copy(it,it+nbOfSubNodes-1,work);
6010 DataArrayInt::SetArrayIn(newConn,_nodal_connec);
6013 _types.insert(INTERP_KERNEL::NORM_POLYGON);
6017 * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
6018 * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
6019 * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell. This method
6020 * does \b not perform geometrical checks and checks only nodal connectivity of cells,
6021 * so it can be useful to call mergeNodes() before calling this method.
6022 * \throw If \a this->getMeshDimension() <= 1.
6023 * \throw If the coordinates array is not set.
6024 * \throw If the nodal connectivity of cells is not defined.
6026 void MEDCouplingUMesh::convertDegeneratedCells()
6028 checkFullyDefined();
6029 if(getMeshDimension()<=1)
6030 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
6031 int nbOfCells=getNumberOfCells();
6034 int initMeshLgth=getNodalConnectivityArrayLen();
6035 int *conn=_nodal_connec->getPointer();
6036 int *index=_nodal_connec_index->getPointer();
6040 for(int i=0;i<nbOfCells;i++)
6042 lgthOfCurCell=index[i+1]-posOfCurCell;
6043 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
6045 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
6046 conn+newPos+1,newLgth);
6047 conn[newPos]=newType;
6049 posOfCurCell=index[i+1];
6052 if(newPos!=initMeshLgth)
6053 _nodal_connec->reAlloc(newPos);
6058 * Finds incorrectly oriented cells of this 2D mesh in 3D space.
6059 * A cell is considered to be oriented correctly if an angle between its
6060 * normal vector and a given vector is less than \c PI / \c 2.
6061 * \param [in] vec - 3 components of the vector specifying the correct orientation of
6063 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
6065 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
6066 * is not cleared before filling in.
6067 * \throw If \a this->getMeshDimension() != 2.
6068 * \throw If \a this->getSpaceDimension() != 3.
6070 * \if ENABLE_EXAMPLES
6071 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
6072 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
6075 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<int>& cells) const
6077 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6078 throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
6079 int nbOfCells=getNumberOfCells();
6080 const int *conn=_nodal_connec->getConstPointer();
6081 const int *connI=_nodal_connec_index->getConstPointer();
6082 const double *coordsPtr=_coords->getConstPointer();
6083 for(int i=0;i<nbOfCells;i++)
6085 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6086 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
6088 bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
6089 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6096 * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
6097 * considered to be oriented correctly if an angle between its normal vector and a
6098 * given vector is less than \c PI / \c 2.
6099 * \param [in] vec - 3 components of the vector specifying the correct orientation of
6101 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
6103 * \throw If \a this->getMeshDimension() != 2.
6104 * \throw If \a this->getSpaceDimension() != 3.
6106 * \if ENABLE_EXAMPLES
6107 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
6108 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
6111 * \sa changeOrientationOfCells
6113 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
6115 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6116 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
6117 int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
6118 const int *connI(_nodal_connec_index->getConstPointer());
6119 const double *coordsPtr(_coords->getConstPointer());
6120 bool isModified(false);
6121 for(int i=0;i<nbOfCells;i++)
6123 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6124 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
6126 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6127 bool isQuadratic(cm.isQuadratic());
6128 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6131 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6136 _nodal_connec->declareAsNew();
6141 * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
6143 * \sa orientCorrectly2DCells
6145 void MEDCouplingUMesh::changeOrientationOfCells()
6147 int mdim(getMeshDimension());
6148 if(mdim!=2 && mdim!=1)
6149 throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
6150 int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
6151 const int *connI(_nodal_connec_index->getConstPointer());
6154 for(int i=0;i<nbOfCells;i++)
6156 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6157 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6158 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6163 for(int i=0;i<nbOfCells;i++)
6165 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6166 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6167 cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6173 * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
6174 * oriented facets. The normal vector of the facet should point out of the cell.
6175 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
6176 * is not cleared before filling in.
6177 * \throw If \a this->getMeshDimension() != 3.
6178 * \throw If \a this->getSpaceDimension() != 3.
6179 * \throw If the coordinates array is not set.
6180 * \throw If the nodal connectivity of cells is not defined.
6182 * \if ENABLE_EXAMPLES
6183 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
6184 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
6187 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<int>& cells) const
6189 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6190 throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
6191 int nbOfCells=getNumberOfCells();
6192 const int *conn=_nodal_connec->getConstPointer();
6193 const int *connI=_nodal_connec_index->getConstPointer();
6194 const double *coordsPtr=_coords->getConstPointer();
6195 for(int i=0;i<nbOfCells;i++)
6197 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6198 if(type==INTERP_KERNEL::NORM_POLYHED)
6200 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6207 * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
6209 * \throw If \a this->getMeshDimension() != 3.
6210 * \throw If \a this->getSpaceDimension() != 3.
6211 * \throw If the coordinates array is not set.
6212 * \throw If the nodal connectivity of cells is not defined.
6213 * \throw If the reparation fails.
6215 * \if ENABLE_EXAMPLES
6216 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
6217 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
6219 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
6221 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
6223 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6224 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
6225 int nbOfCells=getNumberOfCells();
6226 int *conn=_nodal_connec->getPointer();
6227 const int *connI=_nodal_connec_index->getConstPointer();
6228 const double *coordsPtr=_coords->getConstPointer();
6229 for(int i=0;i<nbOfCells;i++)
6231 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6232 if(type==INTERP_KERNEL::NORM_POLYHED)
6236 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6237 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
6239 catch(INTERP_KERNEL::Exception& e)
6241 std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
6242 throw INTERP_KERNEL::Exception(oss.str().c_str());
6250 * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
6251 * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
6252 * according to which the first facet of the cell should be oriented to have the normal vector
6253 * pointing out of cell.
6254 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of fixed
6255 * cells. The caller is to delete this array using decrRef() as it is no more
6257 * \throw If \a this->getMeshDimension() != 3.
6258 * \throw If \a this->getSpaceDimension() != 3.
6259 * \throw If the coordinates array is not set.
6260 * \throw If the nodal connectivity of cells is not defined.
6262 * \if ENABLE_EXAMPLES
6263 * \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
6264 * \ref py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
6266 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
6268 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
6270 const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
6271 if(getMeshDimension()!=3)
6272 throw INTERP_KERNEL::Exception(msg);
6273 int spaceDim=getSpaceDimension();
6275 throw INTERP_KERNEL::Exception(msg);
6277 int nbOfCells=getNumberOfCells();
6278 int *conn=_nodal_connec->getPointer();
6279 const int *connI=_nodal_connec_index->getConstPointer();
6280 const double *coo=getCoords()->getConstPointer();
6281 MCAuto<DataArrayInt> cells(DataArrayInt::New()); cells->alloc(0,1);
6282 for(int i=0;i<nbOfCells;i++)
6284 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6285 if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
6287 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
6289 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
6290 cells->pushBackSilent(i);
6294 return cells.retn();
6298 * This method is a faster method to correct orientation of all 3D cells in \a this.
6299 * 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.
6300 * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
6302 * \return a newly allocated int array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
6303 * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
6305 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
6307 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6308 throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
6309 int nbOfCells=getNumberOfCells();
6310 int *conn=_nodal_connec->getPointer();
6311 const int *connI=_nodal_connec_index->getConstPointer();
6312 const double *coordsPtr=_coords->getConstPointer();
6313 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
6314 for(int i=0;i<nbOfCells;i++)
6316 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6319 case INTERP_KERNEL::NORM_TETRA4:
6321 if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6323 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
6324 ret->pushBackSilent(i);
6328 case INTERP_KERNEL::NORM_PYRA5:
6330 if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6332 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
6333 ret->pushBackSilent(i);
6337 case INTERP_KERNEL::NORM_PENTA6:
6338 case INTERP_KERNEL::NORM_HEXA8:
6339 case INTERP_KERNEL::NORM_HEXGP12:
6341 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6343 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
6344 ret->pushBackSilent(i);
6348 case INTERP_KERNEL::NORM_POLYHED:
6350 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6352 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
6353 ret->pushBackSilent(i);
6358 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 !");
6366 * This method has a sense for meshes with spaceDim==3 and meshDim==2.
6367 * If it is not the case an exception will be thrown.
6368 * This method is fast because the first cell of \a this is used to compute the plane.
6369 * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
6370 * \param pos output of size at least 3 used to store a point owned of searched plane.
6372 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
6374 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6375 throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
6376 const int *conn=_nodal_connec->getConstPointer();
6377 const int *connI=_nodal_connec_index->getConstPointer();
6378 const double *coordsPtr=_coords->getConstPointer();
6379 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
6380 std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
6384 * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
6385 * cells. Currently cells of the following types are treated:
6386 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
6387 * For a cell of other type an exception is thrown.
6388 * Space dimension of a 2D mesh can be either 2 or 3.
6389 * The Edge Ratio of a cell \f$t\f$ is:
6390 * \f$\frac{|t|_\infty}{|t|_0}\f$,
6391 * where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
6392 * the smallest edge lengths of \f$t\f$.
6393 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6394 * cells and one time, lying on \a this mesh. The caller is to delete this
6395 * field using decrRef() as it is no more needed.
6396 * \throw If the coordinates array is not set.
6397 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6398 * \throw If the connectivity data array has more than one component.
6399 * \throw If the connectivity data array has a named component.
6400 * \throw If the connectivity index data array has more than one component.
6401 * \throw If the connectivity index data array has a named component.
6402 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
6403 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
6404 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
6406 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
6408 checkConsistencyLight();
6409 int spaceDim=getSpaceDimension();
6410 int meshDim=getMeshDimension();
6411 if(spaceDim!=2 && spaceDim!=3)
6412 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
6413 if(meshDim!=2 && meshDim!=3)
6414 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
6415 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6417 int nbOfCells=getNumberOfCells();
6418 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6419 arr->alloc(nbOfCells,1);
6420 double *pt=arr->getPointer();
6421 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6422 const int *conn=_nodal_connec->getConstPointer();
6423 const int *connI=_nodal_connec_index->getConstPointer();
6424 const double *coo=_coords->getConstPointer();
6426 for(int i=0;i<nbOfCells;i++,pt++)
6428 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6431 case INTERP_KERNEL::NORM_TRI3:
6433 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
6434 *pt=INTERP_KERNEL::triEdgeRatio(tmp);
6437 case INTERP_KERNEL::NORM_QUAD4:
6439 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6440 *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
6443 case INTERP_KERNEL::NORM_TETRA4:
6445 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6446 *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
6450 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
6452 conn+=connI[i+1]-connI[i];
6454 ret->setName("EdgeRatio");
6455 ret->synchronizeTimeWithSupport();
6460 * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
6461 * cells. Currently cells of the following types are treated:
6462 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
6463 * For a cell of other type an exception is thrown.
6464 * Space dimension of a 2D mesh can be either 2 or 3.
6465 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6466 * cells and one time, lying on \a this mesh. The caller is to delete this
6467 * field using decrRef() as it is no more needed.
6468 * \throw If the coordinates array is not set.
6469 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6470 * \throw If the connectivity data array has more than one component.
6471 * \throw If the connectivity data array has a named component.
6472 * \throw If the connectivity index data array has more than one component.
6473 * \throw If the connectivity index data array has a named component.
6474 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
6475 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
6476 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
6478 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
6480 checkConsistencyLight();
6481 int spaceDim=getSpaceDimension();
6482 int meshDim=getMeshDimension();
6483 if(spaceDim!=2 && spaceDim!=3)
6484 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
6485 if(meshDim!=2 && meshDim!=3)
6486 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
6487 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6489 int nbOfCells=getNumberOfCells();
6490 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6491 arr->alloc(nbOfCells,1);
6492 double *pt=arr->getPointer();
6493 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6494 const int *conn=_nodal_connec->getConstPointer();
6495 const int *connI=_nodal_connec_index->getConstPointer();
6496 const double *coo=_coords->getConstPointer();
6498 for(int i=0;i<nbOfCells;i++,pt++)
6500 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6503 case INTERP_KERNEL::NORM_TRI3:
6505 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
6506 *pt=INTERP_KERNEL::triAspectRatio(tmp);
6509 case INTERP_KERNEL::NORM_QUAD4:
6511 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6512 *pt=INTERP_KERNEL::quadAspectRatio(tmp);
6515 case INTERP_KERNEL::NORM_TETRA4:
6517 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6518 *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
6522 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
6524 conn+=connI[i+1]-connI[i];
6526 ret->setName("AspectRatio");
6527 ret->synchronizeTimeWithSupport();
6532 * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
6533 * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
6534 * in 3D space. Currently only cells of the following types are
6535 * treated: INTERP_KERNEL::NORM_QUAD4.
6536 * For a cell of other type an exception is thrown.
6537 * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
6539 * \f$t=\vec{da}\times\vec{ab}\f$,
6540 * \f$u=\vec{ab}\times\vec{bc}\f$
6541 * \f$v=\vec{bc}\times\vec{cd}\f$
6542 * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
6544 * W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
6546 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6547 * cells and one time, lying on \a this mesh. The caller is to delete this
6548 * field using decrRef() as it is no more needed.
6549 * \throw If the coordinates array is not set.
6550 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6551 * \throw If the connectivity data array has more than one component.
6552 * \throw If the connectivity data array has a named component.
6553 * \throw If the connectivity index data array has more than one component.
6554 * \throw If the connectivity index data array has a named component.
6555 * \throw If \a this->getMeshDimension() != 2.
6556 * \throw If \a this->getSpaceDimension() != 3.
6557 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
6559 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
6561 checkConsistencyLight();
6562 int spaceDim=getSpaceDimension();
6563 int meshDim=getMeshDimension();
6565 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
6567 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
6568 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6570 int nbOfCells=getNumberOfCells();
6571 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6572 arr->alloc(nbOfCells,1);
6573 double *pt=arr->getPointer();
6574 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6575 const int *conn=_nodal_connec->getConstPointer();
6576 const int *connI=_nodal_connec_index->getConstPointer();
6577 const double *coo=_coords->getConstPointer();
6579 for(int i=0;i<nbOfCells;i++,pt++)
6581 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6584 case INTERP_KERNEL::NORM_QUAD4:
6586 FillInCompact3DMode(3,4,conn+1,coo,tmp);
6587 *pt=INTERP_KERNEL::quadWarp(tmp);
6591 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
6593 conn+=connI[i+1]-connI[i];
6595 ret->setName("Warp");
6596 ret->synchronizeTimeWithSupport();
6602 * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
6603 * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
6604 * treated: INTERP_KERNEL::NORM_QUAD4.
6605 * The skew is computed as follow for a quad with points (a,b,c,d): let
6606 * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
6607 * then the skew is computed as:
6609 * s=\frac{u}{|u|}\cdot\frac{v}{|v|}
6612 * For a cell of other type an exception is thrown.
6613 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6614 * cells and one time, lying on \a this mesh. The caller is to delete this
6615 * field using decrRef() as it is no more needed.
6616 * \throw If the coordinates array is not set.
6617 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6618 * \throw If the connectivity data array has more than one component.
6619 * \throw If the connectivity data array has a named component.
6620 * \throw If the connectivity index data array has more than one component.
6621 * \throw If the connectivity index data array has a named component.
6622 * \throw If \a this->getMeshDimension() != 2.
6623 * \throw If \a this->getSpaceDimension() != 3.
6624 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
6626 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
6628 checkConsistencyLight();
6629 int spaceDim=getSpaceDimension();
6630 int meshDim=getMeshDimension();
6632 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
6634 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
6635 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6637 int nbOfCells=getNumberOfCells();
6638 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6639 arr->alloc(nbOfCells,1);
6640 double *pt=arr->getPointer();
6641 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6642 const int *conn=_nodal_connec->getConstPointer();
6643 const int *connI=_nodal_connec_index->getConstPointer();
6644 const double *coo=_coords->getConstPointer();
6646 for(int i=0;i<nbOfCells;i++,pt++)
6648 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6651 case INTERP_KERNEL::NORM_QUAD4:
6653 FillInCompact3DMode(3,4,conn+1,coo,tmp);
6654 *pt=INTERP_KERNEL::quadSkew(tmp);
6658 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
6660 conn+=connI[i+1]-connI[i];
6662 ret->setName("Skew");
6663 ret->synchronizeTimeWithSupport();
6668 * 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.
6670 * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
6672 * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
6674 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
6676 checkConsistencyLight();
6677 MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
6679 std::set<INTERP_KERNEL::NormalizedCellType> types;
6680 ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
6681 int spaceDim(getSpaceDimension()),nbCells(getNumberOfCells());
6682 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6683 arr->alloc(nbCells,1);
6684 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
6686 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
6687 MCAuto<DataArrayInt> cellIds(giveCellsWithType(*it));
6688 dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
6691 ret->setName("Diameter");
6696 * This method aggregate the bbox of each cell and put it into bbox parameter.
6698 * \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)
6699 * For all other cases this input parameter is ignored.
6700 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6702 * \throw If \a this is not fully set (coordinates and connectivity).
6703 * \throw If a cell in \a this has no valid nodeId.
6704 * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
6706 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
6708 int mDim(getMeshDimension()),sDim(getSpaceDimension());
6709 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.
6710 return getBoundingBoxForBBTreeFast();
6711 if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
6713 bool presenceOfQuadratic(false);
6714 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
6716 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
6717 if(cm.isQuadratic())
6718 presenceOfQuadratic=true;
6720 if(!presenceOfQuadratic)
6721 return getBoundingBoxForBBTreeFast();
6722 if(mDim==2 && sDim==2)
6723 return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
6725 return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
6727 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) !");
6731 * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
6732 * So meshes having quadratic cells the computed bounding boxes can be invalid !
6734 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6736 * \throw If \a this is not fully set (coordinates and connectivity).
6737 * \throw If a cell in \a this has no valid nodeId.
6739 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
6741 checkFullyDefined();
6742 int spaceDim(getSpaceDimension()),nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
6743 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6744 double *bbox(ret->getPointer());
6745 for(int i=0;i<nbOfCells*spaceDim;i++)
6747 bbox[2*i]=std::numeric_limits<double>::max();
6748 bbox[2*i+1]=-std::numeric_limits<double>::max();
6750 const double *coordsPtr(_coords->getConstPointer());
6751 const int *conn(_nodal_connec->getConstPointer()),*connI(_nodal_connec_index->getConstPointer());
6752 for(int i=0;i<nbOfCells;i++)
6754 int offset=connI[i]+1;
6755 int nbOfNodesForCell(connI[i+1]-offset),kk(0);
6756 for(int j=0;j<nbOfNodesForCell;j++)
6758 int nodeId=conn[offset+j];
6759 if(nodeId>=0 && nodeId<nbOfNodes)
6761 for(int k=0;k<spaceDim;k++)
6763 bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
6764 bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
6771 std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
6772 throw INTERP_KERNEL::Exception(oss.str().c_str());
6779 * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
6780 * useful for 2D meshes having quadratic cells
6781 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
6782 * the two extremities of the arc of circle).
6784 * \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)
6785 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6786 * \throw If \a this is not fully defined.
6787 * \throw If \a this is not a mesh with meshDimension equal to 2.
6788 * \throw If \a this is not a mesh with spaceDimension equal to 2.
6789 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
6791 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
6793 checkFullyDefined();
6794 int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
6795 if(spaceDim!=2 || mDim!=2)
6796 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!");
6797 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6798 double *bbox(ret->getPointer());
6799 const double *coords(_coords->getConstPointer());
6800 const int *conn(_nodal_connec->getConstPointer()),*connI(_nodal_connec_index->getConstPointer());
6801 for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
6803 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
6804 int sz(connI[1]-connI[0]-1);
6805 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=arcDetEps;
6806 std::vector<INTERP_KERNEL::Node *> nodes(sz);
6807 INTERP_KERNEL::QuadraticPolygon *pol(0);
6808 for(int j=0;j<sz;j++)
6810 int nodeId(conn[*connI+1+j]);
6811 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
6813 if(!cm.isQuadratic())
6814 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
6816 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
6817 INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
6818 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
6824 * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
6825 * useful for 2D meshes having quadratic cells
6826 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
6827 * the two extremities of the arc of circle).
6829 * \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)
6830 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6831 * \throw If \a this is not fully defined.
6832 * \throw If \a this is not a mesh with meshDimension equal to 1.
6833 * \throw If \a this is not a mesh with spaceDimension equal to 2.
6834 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
6836 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
6838 checkFullyDefined();
6839 int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
6840 if(spaceDim!=2 || mDim!=1)
6841 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!");
6842 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6843 double *bbox(ret->getPointer());
6844 const double *coords(_coords->getConstPointer());
6845 const int *conn(_nodal_connec->getConstPointer()),*connI(_nodal_connec_index->getConstPointer());
6846 for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
6848 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
6849 int sz(connI[1]-connI[0]-1);
6850 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=arcDetEps;
6851 std::vector<INTERP_KERNEL::Node *> nodes(sz);
6852 INTERP_KERNEL::Edge *edge(0);
6853 for(int j=0;j<sz;j++)
6855 int nodeId(conn[*connI+1+j]);
6856 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
6858 if(!cm.isQuadratic())
6859 edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
6861 edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
6862 const INTERP_KERNEL::Bounds& b(edge->getBounds());
6863 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
6870 namespace MEDCouplingImpl
6875 ConnReader(const int *c, int val):_conn(c),_val(val) { }
6876 bool operator() (const int& pos) { return _conn[pos]!=_val; }
6885 ConnReader2(const int *c, int val):_conn(c),_val(val) { }
6886 bool operator() (const int& pos) { return _conn[pos]==_val; }
6896 * This method expects that \a this is sorted by types. If not an exception will be thrown.
6897 * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
6898 * \a this is composed in cell types.
6899 * The returned array is of size 3*n where n is the number of different types present in \a this.
6900 * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
6901 * This parameter is kept only for compatibility with other methode listed above.
6903 std::vector<int> MEDCouplingUMesh::getDistributionOfTypes() const
6905 checkConnectivityFullyDefined();
6906 const int *conn=_nodal_connec->getConstPointer();
6907 const int *connI=_nodal_connec_index->getConstPointer();
6908 const int *work=connI;
6909 int nbOfCells=getNumberOfCells();
6910 std::size_t n=getAllGeoTypes().size();
6911 std::vector<int> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
6912 std::set<INTERP_KERNEL::NormalizedCellType> types;
6913 for(std::size_t i=0;work!=connI+nbOfCells;i++)
6915 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
6916 if(types.find(typ)!=types.end())
6918 std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
6919 oss << " is not contiguous !";
6920 throw INTERP_KERNEL::Exception(oss.str().c_str());
6924 const int *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
6925 ret[3*i+1]=(int)std::distance(work,work2);
6932 * This method is used to check that this has contiguous cell type in same order than described in \a code.
6933 * only for types cell, type node is not managed.
6934 * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
6935 * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
6936 * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
6937 * If 2 or more same geometric type is in \a code and exception is thrown too.
6939 * This method firstly checks
6940 * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
6941 * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
6942 * an exception is thrown too.
6944 * If all geometric types in \a code are exactly those in \a this null pointer is returned.
6945 * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
6946 * and a DataArrayInt instance is returned that the user has the responsability to deallocate.
6948 DataArrayInt *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<int>& code, const std::vector<const DataArrayInt *>& idsPerType) const
6951 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
6952 std::size_t sz=code.size();
6955 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
6956 std::vector<INTERP_KERNEL::NormalizedCellType> types;
6958 bool isNoPflUsed=true;
6959 for(std::size_t i=0;i<n;i++)
6960 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
6962 types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
6964 if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
6965 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
6966 isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
6969 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
6972 if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
6973 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
6974 if(types.size()==_types.size())
6977 MCAuto<DataArrayInt> ret=DataArrayInt::New();
6979 int *retPtr=ret->getPointer();
6980 const int *connI=_nodal_connec_index->getConstPointer();
6981 const int *conn=_nodal_connec->getConstPointer();
6982 int nbOfCells=getNumberOfCells();
6985 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
6987 i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,(int)(*it)));
6988 int offset=(int)std::distance(connI,i);
6989 const int *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)(*it)));
6990 int nbOfCellsOfCurType=(int)std::distance(i,j);
6991 if(code[3*kk+2]==-1)
6992 for(int k=0;k<nbOfCellsOfCurType;k++)
6996 int idInIdsPerType=code[3*kk+2];
6997 if(idInIdsPerType>=0 && idInIdsPerType<(int)idsPerType.size())
6999 const DataArrayInt *zePfl=idsPerType[idInIdsPerType];
7002 zePfl->checkAllocated();
7003 if(zePfl->getNumberOfComponents()==1)
7005 for(const int *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
7007 if(*k>=0 && *k<nbOfCellsOfCurType)
7008 *retPtr=(*k)+offset;
7011 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
7012 oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
7013 throw INTERP_KERNEL::Exception(oss.str().c_str());
7018 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
7021 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
7025 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
7026 oss << " should be in [0," << idsPerType.size() << ") !";
7027 throw INTERP_KERNEL::Exception(oss.str().c_str());
7036 * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
7037 * 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.
7038 * 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.
7039 * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
7041 * \param [in] profile
7042 * \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.
7043 * \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,
7044 * \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
7045 * \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.
7046 * This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
7047 * \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
7049 void MEDCouplingUMesh::splitProfilePerType(const DataArrayInt *profile, std::vector<int>& code, std::vector<DataArrayInt *>& idsInPflPerType, std::vector<DataArrayInt *>& idsPerType) const
7052 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
7053 if(profile->getNumberOfComponents()!=1)
7054 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
7055 checkConnectivityFullyDefined();
7056 const int *conn=_nodal_connec->getConstPointer();
7057 const int *connI=_nodal_connec_index->getConstPointer();
7058 int nbOfCells=getNumberOfCells();
7059 std::vector<INTERP_KERNEL::NormalizedCellType> types;
7060 std::vector<int> typeRangeVals(1);
7061 for(const int *i=connI;i!=connI+nbOfCells;)
7063 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7064 if(std::find(types.begin(),types.end(),curType)!=types.end())
7066 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
7068 types.push_back(curType);
7069 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7070 typeRangeVals.push_back((int)std::distance(connI,i));
7073 DataArrayInt *castArr=0,*rankInsideCast=0,*castsPresent=0;
7074 profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
7075 MCAuto<DataArrayInt> tmp0=castArr;
7076 MCAuto<DataArrayInt> tmp1=rankInsideCast;
7077 MCAuto<DataArrayInt> tmp2=castsPresent;
7079 int nbOfCastsFinal=castsPresent->getNumberOfTuples();
7080 code.resize(3*nbOfCastsFinal);
7081 std::vector< MCAuto<DataArrayInt> > idsInPflPerType2;
7082 std::vector< MCAuto<DataArrayInt> > idsPerType2;
7083 for(int i=0;i<nbOfCastsFinal;i++)
7085 int castId=castsPresent->getIJ(i,0);
7086 MCAuto<DataArrayInt> tmp3=castArr->findIdsEqual(castId);
7087 idsInPflPerType2.push_back(tmp3);
7088 code[3*i]=(int)types[castId];
7089 code[3*i+1]=tmp3->getNumberOfTuples();
7090 MCAuto<DataArrayInt> tmp4=rankInsideCast->selectByTupleId(tmp3->getConstPointer(),tmp3->getConstPointer()+tmp3->getNumberOfTuples());
7091 if(!tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
7093 tmp4->copyStringInfoFrom(*profile);
7094 idsPerType2.push_back(tmp4);
7095 code[3*i+2]=(int)idsPerType2.size()-1;
7102 std::size_t sz2=idsInPflPerType2.size();
7103 idsInPflPerType.resize(sz2);
7104 for(std::size_t i=0;i<sz2;i++)
7106 DataArrayInt *locDa=idsInPflPerType2[i];
7108 idsInPflPerType[i]=locDa;
7110 std::size_t sz=idsPerType2.size();
7111 idsPerType.resize(sz);
7112 for(std::size_t i=0;i<sz;i++)
7114 DataArrayInt *locDa=idsPerType2[i];
7116 idsPerType[i]=locDa;
7121 * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
7122 * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
7123 * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
7124 * 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.
7126 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *&revDesc, DataArrayInt *&revDescIndx, DataArrayInt *& nM1LevMeshIds, DataArrayInt *&meshnM1Old2New) const
7128 checkFullyDefined();
7129 nM1LevMesh->checkFullyDefined();
7130 if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
7131 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
7132 if(_coords!=nM1LevMesh->getCoords())
7133 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
7134 MCAuto<DataArrayInt> tmp0=DataArrayInt::New();
7135 MCAuto<DataArrayInt> tmp1=DataArrayInt::New();
7136 MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
7137 MCAuto<DataArrayInt> ret0=ret1->sortCellsInMEDFileFrmt();
7138 desc->transformWithIndArr(ret0->getConstPointer(),ret0->getConstPointer()+ret0->getNbOfElems());
7139 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
7140 tmp->setConnectivity(tmp0,tmp1);
7141 tmp->renumberCells(ret0->getConstPointer(),false);
7142 revDesc=tmp->getNodalConnectivity();
7143 revDescIndx=tmp->getNodalConnectivityIndex();
7144 DataArrayInt *ret=0;
7145 if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
7148 ret->getMaxValue(tmp2);
7150 std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
7151 throw INTERP_KERNEL::Exception(oss.str().c_str());
7156 revDescIndx->incrRef();
7159 meshnM1Old2New=ret0;
7164 * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
7165 * necessary for writing the mesh to MED file. Additionally returns a permutation array
7166 * in "Old to New" mode.
7167 * \return DataArrayInt * - a new instance of DataArrayInt. The caller is to delete
7168 * this array using decrRef() as it is no more needed.
7169 * \throw If the nodal connectivity of cells is not defined.
7171 DataArrayInt *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
7173 checkConnectivityFullyDefined();
7174 MCAuto<DataArrayInt> ret=getRenumArrForMEDFileFrmt();
7175 renumberCells(ret->getConstPointer(),false);
7180 * This methods checks that cells are sorted by their types.
7181 * This method makes asumption (no check) that connectivity is correctly set before calling.
7183 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
7185 checkFullyDefined();
7186 const int *conn=_nodal_connec->getConstPointer();
7187 const int *connI=_nodal_connec_index->getConstPointer();
7188 int nbOfCells=getNumberOfCells();
7189 std::set<INTERP_KERNEL::NormalizedCellType> types;
7190 for(const int *i=connI;i!=connI+nbOfCells;)
7192 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7193 if(types.find(curType)!=types.end())
7195 types.insert(curType);
7196 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7202 * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
7203 * The geometric type order is specified by MED file.
7205 * \sa MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
7207 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
7209 return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
7213 * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
7214 * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
7215 * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
7216 * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
7218 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
7220 checkFullyDefined();
7221 const int *conn=_nodal_connec->getConstPointer();
7222 const int *connI=_nodal_connec_index->getConstPointer();
7223 int nbOfCells=getNumberOfCells();
7227 std::set<INTERP_KERNEL::NormalizedCellType> sg;
7228 for(const int *i=connI;i!=connI+nbOfCells;)
7230 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7231 const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
7232 if(isTypeExists!=orderEnd)
7234 int pos=(int)std::distance(orderBg,isTypeExists);
7238 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7242 if(sg.find(curType)==sg.end())
7244 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7255 * This method returns 2 newly allocated DataArrayInt instances. The first is an array of size 'this->getNumberOfCells()' with one component,
7256 * 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
7257 * 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'.
7259 DataArrayInt *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayInt *&nbPerType) const
7261 checkConnectivityFullyDefined();
7262 int nbOfCells=getNumberOfCells();
7263 const int *conn=_nodal_connec->getConstPointer();
7264 const int *connI=_nodal_connec_index->getConstPointer();
7265 MCAuto<DataArrayInt> tmpa=DataArrayInt::New();
7266 MCAuto<DataArrayInt> tmpb=DataArrayInt::New();
7267 tmpa->alloc(nbOfCells,1);
7268 tmpb->alloc((int)std::distance(orderBg,orderEnd),1);
7269 tmpb->fillWithZero();
7270 int *tmp=tmpa->getPointer();
7271 int *tmp2=tmpb->getPointer();
7272 for(const int *i=connI;i!=connI+nbOfCells;i++)
7274 const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
7277 int pos=(int)std::distance(orderBg,where);
7279 tmp[std::distance(connI,i)]=pos;
7283 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
7284 std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
7285 oss << " has a type " << cm.getRepr() << " not in input array of type !";
7286 throw INTERP_KERNEL::Exception(oss.str().c_str());
7289 nbPerType=tmpb.retn();
7294 * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
7296 * \return a new object containing the old to new correspondance.
7298 * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
7300 DataArrayInt *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
7302 return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
7306 * 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.
7307 * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
7308 * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
7309 * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
7311 DataArrayInt *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
7313 DataArrayInt *nbPerType=0;
7314 MCAuto<DataArrayInt> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
7315 nbPerType->decrRef();
7316 return tmpa->buildPermArrPerLevel();
7320 * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
7321 * The number of cells remains unchanged after the call of this method.
7322 * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
7323 * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
7325 * \return the array giving the correspondance old to new.
7327 DataArrayInt *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
7329 checkFullyDefined();
7331 const int *conn=_nodal_connec->getConstPointer();
7332 const int *connI=_nodal_connec_index->getConstPointer();
7333 int nbOfCells=getNumberOfCells();
7334 std::vector<INTERP_KERNEL::NormalizedCellType> types;
7335 for(const int *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
7336 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
7338 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7339 types.push_back(curType);
7340 for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
7342 DataArrayInt *ret=DataArrayInt::New();
7343 ret->alloc(nbOfCells,1);
7344 int *retPtr=ret->getPointer();
7345 std::fill(retPtr,retPtr+nbOfCells,-1);
7347 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
7349 for(const int *i=connI;i!=connI+nbOfCells;i++)
7350 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
7351 retPtr[std::distance(connI,i)]=newCellId++;
7353 renumberCells(retPtr,false);
7358 * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
7359 * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
7360 * This method makes asumption that connectivity is correctly set before calling.
7362 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
7364 checkConnectivityFullyDefined();
7365 const int *conn=_nodal_connec->getConstPointer();
7366 const int *connI=_nodal_connec_index->getConstPointer();
7367 int nbOfCells=getNumberOfCells();
7368 std::vector<MEDCouplingUMesh *> ret;
7369 for(const int *i=connI;i!=connI+nbOfCells;)
7371 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7372 int beginCellId=(int)std::distance(connI,i);
7373 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7374 int endCellId=(int)std::distance(connI,i);
7375 int sz=endCellId-beginCellId;
7376 int *cells=new int[sz];
7377 for(int j=0;j<sz;j++)
7378 cells[j]=beginCellId+j;
7379 MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
7387 * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
7388 * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
7389 * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
7391 * \return a newly allocated instance, that the caller must manage.
7392 * \throw If \a this contains more than one geometric type.
7393 * \throw If the nodal connectivity of \a this is not fully defined.
7394 * \throw If the internal data is not coherent.
7396 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
7398 checkConnectivityFullyDefined();
7399 if(_types.size()!=1)
7400 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7401 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
7402 MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
7403 ret->setCoords(getCoords());
7404 MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
7407 MCAuto<DataArrayInt> c=convertNodalConnectivityToStaticGeoTypeMesh();
7408 retC->setNodalConnectivity(c);
7412 MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
7414 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
7415 DataArrayInt *c=0,*ci=0;
7416 convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
7417 MCAuto<DataArrayInt> cs(c),cis(ci);
7418 retD->setNodalConnectivity(cs,cis);
7423 DataArrayInt *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
7425 checkConnectivityFullyDefined();
7426 if(_types.size()!=1)
7427 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7428 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
7429 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
7432 std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
7433 oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
7434 throw INTERP_KERNEL::Exception(oss.str().c_str());
7436 int nbCells=getNumberOfCells();
7438 int nbNodesPerCell=(int)cm.getNumberOfNodes();
7439 MCAuto<DataArrayInt> connOut=DataArrayInt::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
7440 int *outPtr=connOut->getPointer();
7441 const int *conn=_nodal_connec->begin();
7442 const int *connI=_nodal_connec_index->begin();
7444 for(int i=0;i<nbCells;i++,connI++)
7446 if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
7447 outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
7450 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 << ") !";
7451 throw INTERP_KERNEL::Exception(oss.str().c_str());
7454 return connOut.retn();
7458 * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
7459 * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
7463 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayInt *&nodalConn, DataArrayInt *&nodalConnIndex) const
7465 static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
7466 checkConnectivityFullyDefined();
7467 if(_types.size()!=1)
7468 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7469 int nbCells=getNumberOfCells(),lgth=_nodal_connec->getNumberOfTuples();
7471 throw INTERP_KERNEL::Exception(msg0);
7472 MCAuto<DataArrayInt> c(DataArrayInt::New()),ci(DataArrayInt::New());
7473 c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
7474 int *cp(c->getPointer()),*cip(ci->getPointer());
7475 const int *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
7477 for(int i=0;i<nbCells;i++,cip++,incip++)
7479 int strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
7480 int delta(stop-strt);
7483 if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
7484 cp=std::copy(incp+strt,incp+stop,cp);
7486 throw INTERP_KERNEL::Exception(msg0);
7489 throw INTERP_KERNEL::Exception(msg0);
7490 cip[1]=cip[0]+delta;
7492 nodalConn=c.retn(); nodalConnIndex=ci.retn();
7496 * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
7497 * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
7498 * This method is particulary useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
7499 * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
7500 * are not used here to avoid the build of big permutation array.
7502 * \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
7503 * those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
7504 * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayInt instance whose number of tuples is equal to the number of chunks of same geotype
7505 * in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
7506 * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayInt instance having the same size than \b szOfCellGrpOfSameType. This
7507 * output array gives for each chunck of same type the corresponding mesh id in \b ms.
7508 * \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
7509 * is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
7511 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
7512 DataArrayInt *&szOfCellGrpOfSameType,
7513 DataArrayInt *&idInMsOfCellGrpOfSameType)
7515 std::vector<const MEDCouplingUMesh *> ms2;
7516 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
7519 (*it)->checkConnectivityFullyDefined();
7523 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
7524 const DataArrayDouble *refCoo=ms2[0]->getCoords();
7525 int meshDim=ms2[0]->getMeshDimension();
7526 std::vector<const MEDCouplingUMesh *> m1ssm;
7527 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
7529 std::vector<const MEDCouplingUMesh *> m1ssmSingle;
7530 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
7532 MCAuto<DataArrayInt> ret1(DataArrayInt::New()),ret2(DataArrayInt::New());
7533 ret1->alloc(0,1); ret2->alloc(0,1);
7534 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
7536 if(meshDim!=(*it)->getMeshDimension())
7537 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
7538 if(refCoo!=(*it)->getCoords())
7539 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
7540 std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
7541 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
7542 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
7543 for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
7545 MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
7546 m1ssmSingleAuto.push_back(singleCell);
7547 m1ssmSingle.push_back(singleCell);
7548 ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
7551 MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
7552 MCAuto<DataArrayInt> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
7553 std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
7554 for(std::size_t i=0;i<m1ssm.size();i++)
7555 m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
7556 MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
7557 szOfCellGrpOfSameType=ret1->renumber(renum->getConstPointer());
7558 idInMsOfCellGrpOfSameType=ret2->renumber(renum->getConstPointer());
7563 * This method returns a newly created DataArrayInt instance.
7564 * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
7566 DataArrayInt *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const int *begin, const int *end) const
7568 checkFullyDefined();
7569 const int *conn=_nodal_connec->getConstPointer();
7570 const int *connIndex=_nodal_connec_index->getConstPointer();
7571 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
7572 for(const int *w=begin;w!=end;w++)
7573 if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
7574 ret->pushBackSilent(*w);
7579 * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
7580 * are in [0:getNumberOfCells())
7582 DataArrayInt *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayInt *da) const
7584 checkFullyDefined();
7585 const int *conn=_nodal_connec->getConstPointer();
7586 const int *connI=_nodal_connec_index->getConstPointer();
7587 int nbOfCells=getNumberOfCells();
7588 std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
7589 int *tmp=new int[nbOfCells];
7590 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
7593 for(const int *i=connI;i!=connI+nbOfCells;i++)
7594 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
7595 tmp[std::distance(connI,i)]=j++;
7597 DataArrayInt *ret=DataArrayInt::New();
7598 ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
7599 ret->copyStringInfoFrom(*da);
7600 int *retPtr=ret->getPointer();
7601 const int *daPtr=da->getConstPointer();
7602 int nbOfElems=da->getNbOfElems();
7603 for(int k=0;k<nbOfElems;k++)
7604 retPtr[k]=tmp[daPtr[k]];
7610 * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
7611 * This method \b works \b for mesh sorted by type.
7612 * cells whose ids is in 'idsPerGeoType' array.
7613 * This method conserves coords and name of mesh.
7615 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const int *idsPerGeoTypeBg, const int *idsPerGeoTypeEnd) const
7617 std::vector<int> code=getDistributionOfTypes();
7618 std::size_t nOfTypesInThis=code.size()/3;
7619 int sz=0,szOfType=0;
7620 for(std::size_t i=0;i<nOfTypesInThis;i++)
7625 szOfType=code[3*i+1];
7627 for(const int *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
7628 if(*work<0 || *work>=szOfType)
7630 std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
7631 oss << ". It should be in [0," << szOfType << ") !";
7632 throw INTERP_KERNEL::Exception(oss.str().c_str());
7634 MCAuto<DataArrayInt> idsTokeep=DataArrayInt::New(); idsTokeep->alloc(sz+(int)std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
7635 int *idsPtr=idsTokeep->getPointer();
7637 for(std::size_t i=0;i<nOfTypesInThis;i++)
7640 for(int j=0;j<code[3*i+1];j++)
7643 idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind2nd(std::plus<int>(),offset));
7644 offset+=code[3*i+1];
7646 MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
7647 ret->copyTinyInfoFrom(this);
7652 * This method returns a vector of size 'this->getNumberOfCells()'.
7653 * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
7655 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
7657 int ncell=getNumberOfCells();
7658 std::vector<bool> ret(ncell);
7659 const int *cI=getNodalConnectivityIndex()->getConstPointer();
7660 const int *c=getNodalConnectivity()->getConstPointer();
7661 for(int i=0;i<ncell;i++)
7663 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
7664 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
7665 ret[i]=cm.isQuadratic();
7671 * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
7673 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
7675 if(other->getType()!=UNSTRUCTURED)
7676 throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
7677 const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
7678 return MergeUMeshes(this,otherC);
7682 * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
7683 * computed by averaging coordinates of cell nodes, so this method is not a right
7684 * choice for degnerated meshes (not well oriented, cells with measure close to zero).
7685 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
7686 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
7687 * components. The caller is to delete this array using decrRef() as it is
7689 * \throw If the coordinates array is not set.
7690 * \throw If the nodal connectivity of cells is not defined.
7691 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
7693 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
7695 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
7696 int spaceDim=getSpaceDimension();
7697 int nbOfCells=getNumberOfCells();
7698 ret->alloc(nbOfCells,spaceDim);
7699 ret->copyStringInfoFrom(*getCoords());
7700 double *ptToFill=ret->getPointer();
7701 const int *nodal=_nodal_connec->getConstPointer();
7702 const int *nodalI=_nodal_connec_index->getConstPointer();
7703 const double *coor=_coords->getConstPointer();
7704 for(int i=0;i<nbOfCells;i++)
7706 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
7707 INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
7714 * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
7715 * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
7717 * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
7718 * DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
7720 * \sa MEDCouplingUMesh::computeCellCenterOfMass
7721 * \throw If \a this is not fully defined (coordinates and connectivity)
7722 * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
7724 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
7726 checkFullyDefined();
7727 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
7728 int spaceDim=getSpaceDimension();
7729 int nbOfCells=getNumberOfCells();
7730 int nbOfNodes=getNumberOfNodes();
7731 ret->alloc(nbOfCells,spaceDim);
7732 double *ptToFill=ret->getPointer();
7733 const int *nodal=_nodal_connec->getConstPointer();
7734 const int *nodalI=_nodal_connec_index->getConstPointer();
7735 const double *coor=_coords->getConstPointer();
7736 for(int i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
7738 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
7739 std::fill(ptToFill,ptToFill+spaceDim,0.);
7740 if(type!=INTERP_KERNEL::NORM_POLYHED)
7742 for(const int *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
7744 if(*conn>=0 && *conn<nbOfNodes)
7745 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
7748 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," << nbOfNodes << ") !";
7749 throw INTERP_KERNEL::Exception(oss.str().c_str());
7752 int nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
7753 if(nbOfNodesInCell>0)
7754 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
7757 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
7758 throw INTERP_KERNEL::Exception(oss.str().c_str());
7763 std::set<int> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
7765 for(std::set<int>::const_iterator it=s.begin();it!=s.end();it++)
7767 if(*it>=0 && *it<nbOfNodes)
7768 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
7771 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," << nbOfNodes << ") !";
7772 throw INTERP_KERNEL::Exception(oss.str().c_str());
7776 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)s.size()));
7779 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
7780 throw INTERP_KERNEL::Exception(oss.str().c_str());
7788 * Returns a new DataArrayDouble holding barycenters of specified cells. The
7789 * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
7790 * are specified via an array of cell ids.
7791 * \warning Validity of the specified cell ids is not checked!
7792 * Valid range is [ 0, \a this->getNumberOfCells() ).
7793 * \param [in] begin - an array of cell ids of interest.
7794 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
7795 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
7796 * end - \a begin ) tuples per \a this->getSpaceDimension() components. The
7797 * caller is to delete this array using decrRef() as it is no more needed.
7798 * \throw If the coordinates array is not set.
7799 * \throw If the nodal connectivity of cells is not defined.
7801 * \if ENABLE_EXAMPLES
7802 * \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
7803 * \ref py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
7806 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const int *begin, const int *end) const
7808 DataArrayDouble *ret=DataArrayDouble::New();
7809 int spaceDim=getSpaceDimension();
7810 int nbOfTuple=(int)std::distance(begin,end);
7811 ret->alloc(nbOfTuple,spaceDim);
7812 double *ptToFill=ret->getPointer();
7813 double *tmp=new double[spaceDim];
7814 const int *nodal=_nodal_connec->getConstPointer();
7815 const int *nodalI=_nodal_connec_index->getConstPointer();
7816 const double *coor=_coords->getConstPointer();
7817 for(const int *w=begin;w!=end;w++)
7819 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
7820 INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
7828 * 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".
7829 * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
7830 * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
7831 * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
7832 * This method is useful to detect 2D cells in 3D space that are not coplanar.
7834 * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
7835 * \throw If spaceDim!=3 or meshDim!=2.
7836 * \throw If connectivity of \a this is invalid.
7837 * \throw If connectivity of a cell in \a this points to an invalid node.
7839 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
7841 MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
7842 int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
7843 if(getSpaceDimension()!=3 || getMeshDimension()!=2)
7844 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
7845 ret->alloc(nbOfCells,4);
7846 double *retPtr(ret->getPointer());
7847 const int *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
7848 const double *coor(_coords->begin());
7849 for(int i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
7851 double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
7852 if(nodalI[1]-nodalI[0]>=3)
7854 for(int j=0;j<3;j++)
7856 int nodeId(nodal[nodalI[0]+1+j]);
7857 if(nodeId>=0 && nodeId<nbOfNodes)
7858 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
7861 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
7862 throw INTERP_KERNEL::Exception(oss.str().c_str());
7868 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
7869 throw INTERP_KERNEL::Exception(oss.str().c_str());
7871 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
7872 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
7878 * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
7881 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
7884 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
7885 da->checkAllocated();
7886 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(da->getName(),0);
7888 int nbOfTuples=da->getNumberOfTuples();
7889 MCAuto<DataArrayInt> c=DataArrayInt::New();
7890 MCAuto<DataArrayInt> cI=DataArrayInt::New();
7891 c->alloc(2*nbOfTuples,1);
7892 cI->alloc(nbOfTuples+1,1);
7893 int *cp=c->getPointer();
7894 int *cip=cI->getPointer();
7896 for(int i=0;i<nbOfTuples;i++)
7898 *cp++=INTERP_KERNEL::NORM_POINT1;
7902 ret->setConnectivity(c,cI,true);
7906 * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
7907 * Cells and nodes of
7908 * the first mesh precede cells and nodes of the second mesh within the result mesh.
7909 * \param [in] mesh1 - the first mesh.
7910 * \param [in] mesh2 - the second mesh.
7911 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7912 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7913 * is no more needed.
7914 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
7915 * \throw If the coordinates array is not set in none of the meshes.
7916 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
7917 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
7919 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
7921 std::vector<const MEDCouplingUMesh *> tmp(2);
7922 tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
7923 return MergeUMeshes(tmp);
7927 * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
7928 * Cells and nodes of
7929 * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
7930 * \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
7931 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7932 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7933 * is no more needed.
7934 * \throw If \a a.size() == 0.
7935 * \throw If \a a[ *i* ] == NULL.
7936 * \throw If the coordinates array is not set in none of the meshes.
7937 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
7938 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
7940 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(std::vector<const MEDCouplingUMesh *>& a)
7942 std::size_t sz=a.size();
7944 return MergeUMeshesLL(a);
7945 for(std::size_t ii=0;ii<sz;ii++)
7948 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
7949 throw INTERP_KERNEL::Exception(oss.str().c_str());
7951 std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
7952 std::vector< const MEDCouplingUMesh * > aa(sz);
7954 for(std::size_t i=0;i<sz && spaceDim==-3;i++)
7956 const MEDCouplingUMesh *cur=a[i];
7957 const DataArrayDouble *coo=cur->getCoords();
7959 spaceDim=coo->getNumberOfComponents();
7962 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
7963 for(std::size_t i=0;i<sz;i++)
7965 bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
7968 return MergeUMeshesLL(aa);
7973 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesLL(std::vector<const MEDCouplingUMesh *>& a)
7976 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : input array must be NON EMPTY !");
7977 std::vector<const MEDCouplingUMesh *>::const_iterator it=a.begin();
7978 int meshDim=(*it)->getMeshDimension();
7979 int nbOfCells=(*it)->getNumberOfCells();
7980 int meshLgth=(*it++)->getNodalConnectivityArrayLen();
7981 for(;it!=a.end();it++)
7983 if(meshDim!=(*it)->getMeshDimension())
7984 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, MergeUMeshes impossible !");
7985 nbOfCells+=(*it)->getNumberOfCells();
7986 meshLgth+=(*it)->getNodalConnectivityArrayLen();
7988 std::vector<const MEDCouplingPointSet *> aps(a.size());
7989 std::copy(a.begin(),a.end(),aps.begin());
7990 MCAuto<DataArrayDouble> pts=MergeNodesArray(aps);
7991 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("merge",meshDim);
7992 ret->setCoords(pts);
7993 MCAuto<DataArrayInt> c=DataArrayInt::New();
7994 c->alloc(meshLgth,1);
7995 int *cPtr=c->getPointer();
7996 MCAuto<DataArrayInt> cI=DataArrayInt::New();
7997 cI->alloc(nbOfCells+1,1);
7998 int *cIPtr=cI->getPointer();
8002 for(it=a.begin();it!=a.end();it++)
8004 int curNbOfCell=(*it)->getNumberOfCells();
8005 const int *curCI=(*it)->_nodal_connec_index->getConstPointer();
8006 const int *curC=(*it)->_nodal_connec->getConstPointer();
8007 cIPtr=std::transform(curCI+1,curCI+curNbOfCell+1,cIPtr,std::bind2nd(std::plus<int>(),offset));
8008 for(int j=0;j<curNbOfCell;j++)
8010 const int *src=curC+curCI[j];
8012 for(;src!=curC+curCI[j+1];src++,cPtr++)
8020 offset+=curCI[curNbOfCell];
8021 offset2+=(*it)->getNumberOfNodes();
8024 ret->setConnectivity(c,cI,true);
8031 * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
8032 * dimension and sharing the node coordinates array.
8033 * All cells of the first mesh precede all cells of the second mesh
8034 * within the result mesh.
8035 * \param [in] mesh1 - the first mesh.
8036 * \param [in] mesh2 - the second mesh.
8037 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8038 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8039 * is no more needed.
8040 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
8041 * \throw If the meshes do not share the node coordinates array.
8042 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
8043 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
8045 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
8047 std::vector<const MEDCouplingUMesh *> tmp(2);
8048 tmp[0]=mesh1; tmp[1]=mesh2;
8049 return MergeUMeshesOnSameCoords(tmp);
8053 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
8054 * dimension and sharing the node coordinates array.
8055 * All cells of the *i*-th mesh precede all cells of the
8056 * (*i*+1)-th mesh within the result mesh.
8057 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
8058 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8059 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8060 * is no more needed.
8061 * \throw If \a a.size() == 0.
8062 * \throw If \a a[ *i* ] == NULL.
8063 * \throw If the meshes do not share the node coordinates array.
8064 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
8065 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
8067 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
8070 throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
8071 for(std::size_t ii=0;ii<meshes.size();ii++)
8074 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
8075 throw INTERP_KERNEL::Exception(oss.str().c_str());
8077 const DataArrayDouble *coords=meshes.front()->getCoords();
8078 int meshDim=meshes.front()->getMeshDimension();
8079 std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
8081 int meshIndexLgth=0;
8082 for(;iter!=meshes.end();iter++)
8084 if(coords!=(*iter)->getCoords())
8085 throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
8086 if(meshDim!=(*iter)->getMeshDimension())
8087 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
8088 meshLgth+=(*iter)->getNodalConnectivityArrayLen();
8089 meshIndexLgth+=(*iter)->getNumberOfCells();
8091 MCAuto<DataArrayInt> nodal=DataArrayInt::New();
8092 nodal->alloc(meshLgth,1);
8093 int *nodalPtr=nodal->getPointer();
8094 MCAuto<DataArrayInt> nodalIndex=DataArrayInt::New();
8095 nodalIndex->alloc(meshIndexLgth+1,1);
8096 int *nodalIndexPtr=nodalIndex->getPointer();
8098 for(iter=meshes.begin();iter!=meshes.end();iter++)
8100 const int *nod=(*iter)->getNodalConnectivity()->getConstPointer();
8101 const int *index=(*iter)->getNodalConnectivityIndex()->getConstPointer();
8102 int nbOfCells=(*iter)->getNumberOfCells();
8103 int meshLgth2=(*iter)->getNodalConnectivityArrayLen();
8104 nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
8105 if(iter!=meshes.begin())
8106 nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind2nd(std::plus<int>(),offset));
8108 nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
8111 MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
8112 ret->setName("merge");
8113 ret->setMeshDimension(meshDim);
8114 ret->setConnectivity(nodal,nodalIndex,true);
8115 ret->setCoords(coords);
8120 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
8121 * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
8122 * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
8123 * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
8124 * New" mode are returned for each input mesh.
8125 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
8126 * \param [in] compType - specifies a cell comparison technique. For meaning of its
8127 * valid values [0,1,2], see zipConnectivityTraducer().
8128 * \param [in,out] corr - an array of DataArrayInt, of the same size as \a
8129 * meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
8130 * mesh. The caller is to delete each of the arrays using decrRef() as it is
8132 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8133 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8134 * is no more needed.
8135 * \throw If \a meshes.size() == 0.
8136 * \throw If \a meshes[ *i* ] == NULL.
8137 * \throw If the meshes do not share the node coordinates array.
8138 * \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
8139 * \throw If the \a meshes are of different dimension (getMeshDimension()).
8140 * \throw If the nodal connectivity of cells of any of \a meshes is not defined.
8141 * \throw If the nodal connectivity any of \a meshes includes an invalid id.
8143 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayInt *>& corr)
8145 //All checks are delegated to MergeUMeshesOnSameCoords
8146 MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
8147 MCAuto<DataArrayInt> o2n=ret->zipConnectivityTraducer(compType);
8148 corr.resize(meshes.size());
8149 std::size_t nbOfMeshes=meshes.size();
8151 const int *o2nPtr=o2n->getConstPointer();
8152 for(std::size_t i=0;i<nbOfMeshes;i++)
8154 DataArrayInt *tmp=DataArrayInt::New();
8155 int curNbOfCells=meshes[i]->getNumberOfCells();
8156 tmp->alloc(curNbOfCells,1);
8157 std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
8158 offset+=curNbOfCells;
8159 tmp->setName(meshes[i]->getName());
8166 * Makes all given meshes share the nodal connectivity array. The common connectivity
8167 * array is created by concatenating the connectivity arrays of all given meshes. All
8168 * the given meshes must be of the same space dimension but dimension of cells **can
8169 * differ**. This method is particulary useful in MEDLoader context to build a \ref
8170 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
8171 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
8172 * \param [in,out] meshes - a vector of meshes to update.
8173 * \throw If any of \a meshes is NULL.
8174 * \throw If the coordinates array is not set in any of \a meshes.
8175 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
8176 * \throw If \a meshes are of different space dimension.
8178 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
8180 std::size_t sz=meshes.size();
8183 std::vector< const DataArrayDouble * > coords(meshes.size());
8184 std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
8185 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
8189 (*it)->checkConnectivityFullyDefined();
8190 const DataArrayDouble *coo=(*it)->getCoords();
8195 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
8196 oss << " has no coordinate array defined !";
8197 throw INTERP_KERNEL::Exception(oss.str().c_str());
8202 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
8203 oss << " is null !";
8204 throw INTERP_KERNEL::Exception(oss.str().c_str());
8207 MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
8208 std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
8209 int offset=(*it)->getNumberOfNodes();
8210 (*it++)->setCoords(res);
8211 for(;it!=meshes.end();it++)
8213 int oldNumberOfNodes=(*it)->getNumberOfNodes();
8214 (*it)->setCoords(res);
8215 (*it)->shiftNodeNumbersInConn(offset);
8216 offset+=oldNumberOfNodes;
8221 * Merges nodes coincident with a given precision within all given meshes that share
8222 * the nodal connectivity array. The given meshes **can be of different** mesh
8223 * dimension. This method is particulary useful in MEDLoader context to build a \ref
8224 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
8225 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
8226 * \param [in,out] meshes - a vector of meshes to update.
8227 * \param [in] eps - the precision used to detect coincident nodes (infinite norm).
8228 * \throw If any of \a meshes is NULL.
8229 * \throw If the \a meshes do not share the same node coordinates array.
8230 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
8232 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
8236 std::set<const DataArrayDouble *> s;
8237 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
8240 s.insert((*it)->getCoords());
8243 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 !";
8244 throw INTERP_KERNEL::Exception(oss.str().c_str());
8249 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 !";
8250 throw INTERP_KERNEL::Exception(oss.str().c_str());
8252 const DataArrayDouble *coo=*(s.begin());
8256 DataArrayInt *comm,*commI;
8257 coo->findCommonTuples(eps,-1,comm,commI);
8258 MCAuto<DataArrayInt> tmp1(comm),tmp2(commI);
8259 int oldNbOfNodes=coo->getNumberOfTuples();
8261 MCAuto<DataArrayInt> o2n=DataArrayInt::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
8262 if(oldNbOfNodes==newNbOfNodes)
8264 MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->getConstPointer(),newNbOfNodes);
8265 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
8267 (*it)->renumberNodesInConn(o2n->getConstPointer());
8268 (*it)->setCoords(newCoords);
8273 * 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.
8274 * \param nbOfNodesPerLev in parameter that specifies the number of nodes of one slice of global dataset
8275 * \param isQuad specifies the policy of connectivity.
8276 * @ret in/out parameter in which the result will be append
8278 void MEDCouplingUMesh::AppendExtrudedCell(const int *connBg, const int *connEnd, int nbOfNodesPerLev, bool isQuad, std::vector<int>& ret)
8280 INTERP_KERNEL::NormalizedCellType flatType=(INTERP_KERNEL::NormalizedCellType)connBg[0];
8281 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(flatType);
8282 ret.push_back(cm.getExtrudedType());
8283 int deltaz=isQuad?2*nbOfNodesPerLev:nbOfNodesPerLev;
8286 case INTERP_KERNEL::NORM_POINT1:
8288 ret.push_back(connBg[1]);
8289 ret.push_back(connBg[1]+nbOfNodesPerLev);
8292 case INTERP_KERNEL::NORM_SEG2:
8294 int conn[4]={connBg[1],connBg[2],connBg[2]+deltaz,connBg[1]+deltaz};
8295 ret.insert(ret.end(),conn,conn+4);
8298 case INTERP_KERNEL::NORM_SEG3:
8300 int conn[8]={connBg[1],connBg[3],connBg[3]+deltaz,connBg[1]+deltaz,connBg[2],connBg[3]+nbOfNodesPerLev,connBg[2]+deltaz,connBg[1]+nbOfNodesPerLev};
8301 ret.insert(ret.end(),conn,conn+8);
8304 case INTERP_KERNEL::NORM_QUAD4:
8306 int conn[8]={connBg[1],connBg[2],connBg[3],connBg[4],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4]+deltaz};
8307 ret.insert(ret.end(),conn,conn+8);
8310 case INTERP_KERNEL::NORM_TRI3:
8312 int conn[6]={connBg[1],connBg[2],connBg[3],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz};
8313 ret.insert(ret.end(),conn,conn+6);
8316 case INTERP_KERNEL::NORM_TRI6:
8318 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,
8319 connBg[1]+nbOfNodesPerLev,connBg[2]+nbOfNodesPerLev,connBg[3]+nbOfNodesPerLev};
8320 ret.insert(ret.end(),conn,conn+15);
8323 case INTERP_KERNEL::NORM_QUAD8:
8326 connBg[1],connBg[2],connBg[3],connBg[4],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4]+deltaz,
8327 connBg[5],connBg[6],connBg[7],connBg[8],connBg[5]+deltaz,connBg[6]+deltaz,connBg[7]+deltaz,connBg[8]+deltaz,
8328 connBg[1]+nbOfNodesPerLev,connBg[2]+nbOfNodesPerLev,connBg[3]+nbOfNodesPerLev,connBg[4]+nbOfNodesPerLev
8330 ret.insert(ret.end(),conn,conn+20);
8333 case INTERP_KERNEL::NORM_POLYGON:
8335 std::back_insert_iterator< std::vector<int> > ii(ret);
8336 std::copy(connBg+1,connEnd,ii);
8338 std::reverse_iterator<const int *> rConnBg(connEnd);
8339 std::reverse_iterator<const int *> rConnEnd(connBg+1);
8340 std::transform(rConnBg,rConnEnd,ii,std::bind2nd(std::plus<int>(),deltaz));
8341 std::size_t nbOfRadFaces=std::distance(connBg+1,connEnd);
8342 for(std::size_t i=0;i<nbOfRadFaces;i++)
8345 int conn[4]={connBg[(i+1)%nbOfRadFaces+1],connBg[i+1],connBg[i+1]+deltaz,connBg[(i+1)%nbOfRadFaces+1]+deltaz};
8346 std::copy(conn,conn+4,ii);
8351 throw INTERP_KERNEL::Exception("A flat type has been detected that has not its extruded representation !");
8356 * This static operates only for coords in 3D. The polygon is specfied by its connectivity nodes in [ \a begin , \a end ).
8358 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const int *begin, const int *end, const double *coords)
8361 double v[3]={0.,0.,0.};
8362 std::size_t sz=std::distance(begin,end);
8367 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];
8368 v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
8369 v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
8371 double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
8373 // Try using quadratic points if standard points are degenerated (for example a QPOLYG with two
8374 // SEG3 forming a circle):
8375 if (fabs(ret) < INTERP_KERNEL::DEFAULT_ABS_TOL && isQuadratic)
8377 v[0] = 0.0; v[1] = 0.0; v[2] = 0.0;
8378 for(std::size_t j=0;j<sz;j++)
8380 if (j%2) // current point i is quadratic, next point i+1 is standard
8383 ip1 = (j+1)%sz; // ip1 = "i+1"
8385 else // current point i is standard, next point i+1 is quadratic
8390 v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
8391 v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
8392 v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
8394 ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
8400 * The polyhedron is specfied by its connectivity nodes in [ \a begin , \a end ).
8402 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const int *begin, const int *end, const double *coords)
8404 std::vector<std::pair<int,int> > edges;
8405 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
8406 const int *bgFace=begin;
8407 for(std::size_t i=0;i<nbOfFaces;i++)
8409 const int *endFace=std::find(bgFace+1,end,-1);
8410 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
8411 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8413 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8414 if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
8416 edges.push_back(p1);
8420 return INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)>-EPS_FOR_POLYH_ORIENTATION;
8424 * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
8426 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const int *begin, const int *end, const double *coords)
8428 double vec0[3],vec1[3];
8429 std::size_t sz=std::distance(begin,end);
8431 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
8432 int nbOfNodes=(int)sz/2;
8433 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
8434 const double *pt0=coords+3*begin[0];
8435 const double *pt1=coords+3*begin[nbOfNodes];
8436 vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
8437 return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
8440 void MEDCouplingUMesh::CorrectExtrudedStaticCell(int *begin, int *end)
8442 std::size_t sz=std::distance(begin,end);
8443 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
8444 std::size_t nbOfNodes(sz/2);
8445 std::copy(begin,end,(int *)tmp);
8446 for(std::size_t j=1;j<nbOfNodes;j++)
8448 begin[j]=tmp[nbOfNodes-j];
8449 begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
8453 bool MEDCouplingUMesh::IsTetra4WellOriented(const int *begin, const int *end, const double *coords)
8455 std::size_t sz=std::distance(begin,end);
8457 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
8458 double vec0[3],vec1[3];
8459 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
8460 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];
8461 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;
8464 bool MEDCouplingUMesh::IsPyra5WellOriented(const int *begin, const int *end, const double *coords)
8466 std::size_t sz=std::distance(begin,end);
8468 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
8470 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
8471 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
8472 return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
8476 * 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 )
8477 * 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
8480 * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
8481 * \param [in] coords the coordinates with nb of components exactly equal to 3
8482 * \param [in] begin begin of the nodal connectivity (geometric type included) of a single polyhedron cell
8483 * \param [in] end end of nodal connectivity of a single polyhedron cell (excluded)
8484 * \param [out] res the result is put at the end of the vector without any alteration of the data.
8486 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, const int *begin, const int *end, DataArrayInt *res)
8488 int nbFaces=std::count(begin+1,end,-1)+1;
8489 MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
8490 double *vPtr=v->getPointer();
8491 MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,1);
8492 double *pPtr=p->getPointer();
8493 const int *stFaceConn=begin+1;
8494 for(int i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
8496 const int *endFaceConn=std::find(stFaceConn,end,-1);
8497 ComputeVecAndPtOfFace(eps,coords->getConstPointer(),stFaceConn,endFaceConn,vPtr,pPtr);
8498 stFaceConn=endFaceConn+1;
8500 pPtr=p->getPointer(); vPtr=v->getPointer();
8501 DataArrayInt *comm1=0,*commI1=0;
8502 v->findCommonTuples(eps,-1,comm1,commI1);
8503 MCAuto<DataArrayInt> comm1Auto(comm1),commI1Auto(commI1);
8504 const int *comm1Ptr=comm1->getConstPointer();
8505 const int *commI1Ptr=commI1->getConstPointer();
8506 int nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
8507 res->pushBackSilent((int)INTERP_KERNEL::NORM_POLYHED);
8509 MCAuto<MEDCouplingUMesh> mm=MEDCouplingUMesh::New("",3);
8510 mm->setCoords(const_cast<DataArrayDouble *>(coords)); mm->allocateCells(1); mm->insertNextCell(INTERP_KERNEL::NORM_POLYHED,(int)std::distance(begin+1,end),begin+1);
8511 mm->finishInsertingCells();
8513 for(int i=0;i<nbOfGrps1;i++)
8515 int vecId=comm1Ptr[commI1Ptr[i]];
8516 MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
8517 DataArrayInt *comm2=0,*commI2=0;
8518 tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
8519 MCAuto<DataArrayInt> comm2Auto(comm2),commI2Auto(commI2);
8520 const int *comm2Ptr=comm2->getConstPointer();
8521 const int *commI2Ptr=commI2->getConstPointer();
8522 int nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
8523 for(int j=0;j<nbOfGrps2;j++)
8525 if(commI2Ptr[j+1]-commI2Ptr[j]<=1)
8527 res->insertAtTheEnd(begin,end);
8528 res->pushBackSilent(-1);
8532 int pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
8533 MCAuto<DataArrayInt> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
8534 ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
8535 DataArrayInt *tmp0=DataArrayInt::New(),*tmp1=DataArrayInt::New(),*tmp2=DataArrayInt::New(),*tmp3=DataArrayInt::New();
8536 MCAuto<MEDCouplingUMesh> mm2=mm->buildDescendingConnectivity(tmp0,tmp1,tmp2,tmp3); tmp0->decrRef(); tmp1->decrRef(); tmp2->decrRef(); tmp3->decrRef();
8537 MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(mm2->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
8538 MCAuto<DataArrayInt> idsNodeTmp=mm3->zipCoordsTraducer();
8539 MCAuto<DataArrayInt> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
8540 const int *idsNodePtr=idsNode->getConstPointer();
8541 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];
8542 double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
8543 double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
8544 if(std::abs(norm)>eps)
8546 double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
8547 mm3->rotate(center,vec,angle);
8549 mm3->changeSpaceDimension(2);
8550 MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
8551 const int *conn4=mm4->getNodalConnectivity()->getConstPointer();
8552 const int *connI4=mm4->getNodalConnectivityIndex()->getConstPointer();
8553 int nbOfCells=mm4->getNumberOfCells();
8554 for(int k=0;k<nbOfCells;k++)
8557 for(const int *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
8558 res->pushBackSilent(idsNodePtr[*work]);
8559 res->pushBackSilent(-1);
8564 res->popBackSilent();
8568 * 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
8569 * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
8571 * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
8572 * \param [in] coords coordinates expected to have 3 components.
8573 * \param [in] begin start of the nodal connectivity of the face.
8574 * \param [in] end end of the nodal connectivity (excluded) of the face.
8575 * \param [out] v the normalized vector of size 3
8576 * \param [out] p the pos of plane
8578 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const int *begin, const int *end, double *v, double *p)
8580 std::size_t nbPoints=std::distance(begin,end);
8582 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
8583 double vec[3]={0.,0.,0.};
8585 bool refFound=false;
8586 for(;j<nbPoints-1 && !refFound;j++)
8588 vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
8589 vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
8590 vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
8591 double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
8595 vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
8598 for(std::size_t i=j;i<nbPoints-1;i++)
8601 curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
8602 curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
8603 curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
8604 double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
8607 curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
8608 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];
8609 norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
8612 v[0]/=norm; v[1]/=norm; v[2]/=norm;
8613 *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
8617 throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
8621 * This method tries to obtain a well oriented polyhedron.
8622 * If the algorithm fails, an exception will be thrown.
8624 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(int *begin, int *end, const double *coords)
8626 std::list< std::pair<int,int> > edgesOK,edgesFinished;
8627 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
8628 std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
8630 int *bgFace=begin,*endFace=std::find(begin+1,end,-1);
8631 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
8632 for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<int,int> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
8634 while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
8637 std::size_t smthChanged=0;
8638 for(std::size_t i=0;i<nbOfFaces;i++)
8640 endFace=std::find(bgFace+1,end,-1);
8641 nbOfEdgesInFace=std::distance(bgFace,endFace);
8645 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8647 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8648 std::pair<int,int> p2(p1.second,p1.first);
8649 bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
8650 bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
8651 if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
8656 std::reverse(bgFace+1,endFace);
8657 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8659 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8660 std::pair<int,int> p2(p1.second,p1.first);
8661 if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
8662 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str().c_str()); }
8663 if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
8664 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str().c_str()); }
8665 std::list< std::pair<int,int> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
8666 if(it!=edgesOK.end())
8669 edgesFinished.push_back(p1);
8672 edgesOK.push_back(p1);
8679 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
8681 if(!edgesOK.empty())
8682 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
8683 if(INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)<-EPS_FOR_POLYH_ORIENTATION)
8684 {//not lucky ! The first face was not correctly oriented : reorient all faces...
8686 for(std::size_t i=0;i<nbOfFaces;i++)
8688 endFace=std::find(bgFace+1,end,-1);
8689 std::reverse(bgFace+1,endFace);
8695 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMeshLinear(const MEDCouplingUMesh *skin, const DataArrayInt *n2o) const
8697 int nbOfNodesExpected(skin->getNumberOfNodes());
8698 const int *n2oPtr(n2o->getConstPointer());
8699 MCAuto<DataArrayInt> revNodal(DataArrayInt::New()),revNodalI(DataArrayInt::New());
8700 skin->getReverseNodalConnectivity(revNodal,revNodalI);
8701 const int *revNodalPtr(revNodal->getConstPointer()),*revNodalIPtr(revNodalI->getConstPointer());
8702 const int *nodalPtr(skin->getNodalConnectivity()->getConstPointer());
8703 const int *nodalIPtr(skin->getNodalConnectivityIndex()->getConstPointer());
8704 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfNodesExpected+1,1);
8705 int *work(ret->getPointer()); *work++=INTERP_KERNEL::NORM_POLYGON;
8706 if(nbOfNodesExpected<1)
8708 int prevCell(0),prevNode(nodalPtr[nodalIPtr[0]+1]);
8709 *work++=n2oPtr[prevNode];
8710 for(int i=1;i<nbOfNodesExpected;i++)
8712 if(nodalIPtr[prevCell+1]-nodalIPtr[prevCell]==3)
8714 std::set<int> conn(nodalPtr+nodalIPtr[prevCell]+1,nodalPtr+nodalIPtr[prevCell]+3);
8715 conn.erase(prevNode);
8718 int curNode(*(conn.begin()));
8719 *work++=n2oPtr[curNode];
8720 std::set<int> shar(revNodalPtr+revNodalIPtr[curNode],revNodalPtr+revNodalIPtr[curNode+1]);
8721 shar.erase(prevCell);
8724 prevCell=*(shar.begin());
8728 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected 2 !");
8731 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected 1 !");
8734 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected cell !");
8739 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMeshQuadratic(const MEDCouplingUMesh *skin, const DataArrayInt *n2o) const
8741 int nbOfNodesExpected(skin->getNumberOfNodes());
8742 int nbOfTurn(nbOfNodesExpected/2);
8743 const int *n2oPtr(n2o->getConstPointer());
8744 MCAuto<DataArrayInt> revNodal(DataArrayInt::New()),revNodalI(DataArrayInt::New());
8745 skin->getReverseNodalConnectivity(revNodal,revNodalI);
8746 const int *revNodalPtr(revNodal->getConstPointer()),*revNodalIPtr(revNodalI->getConstPointer());
8747 const int *nodalPtr(skin->getNodalConnectivity()->getConstPointer());
8748 const int *nodalIPtr(skin->getNodalConnectivityIndex()->getConstPointer());
8749 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfNodesExpected+1,1);
8750 int *work(ret->getPointer()); *work++=INTERP_KERNEL::NORM_QPOLYG;
8751 if(nbOfNodesExpected<1)
8753 int prevCell(0),prevNode(nodalPtr[nodalIPtr[0]+1]);
8754 *work=n2oPtr[prevNode]; work[nbOfTurn]=n2oPtr[nodalPtr[nodalIPtr[0]+3]]; work++;
8755 for(int i=1;i<nbOfTurn;i++)
8757 if(nodalIPtr[prevCell+1]-nodalIPtr[prevCell]==4)
8759 std::set<int> conn(nodalPtr+nodalIPtr[prevCell]+1,nodalPtr+nodalIPtr[prevCell]+3);
8760 conn.erase(prevNode);
8763 int curNode(*(conn.begin()));
8764 *work=n2oPtr[curNode];
8765 std::set<int> shar(revNodalPtr+revNodalIPtr[curNode],revNodalPtr+revNodalIPtr[curNode+1]);
8766 shar.erase(prevCell);
8769 int curCell(*(shar.begin()));
8770 work[nbOfTurn]=n2oPtr[nodalPtr[nodalIPtr[curCell]+3]];
8776 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected 2 !");
8779 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected 1 !");
8782 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected cell !");
8788 * This method makes the assumption spacedimension == meshdimension == 2.
8789 * This method works only for linear cells.
8791 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
8793 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMesh() const
8795 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
8796 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
8797 MCAuto<MEDCouplingUMesh> skin(computeSkin());
8798 int oldNbOfNodes(skin->getNumberOfNodes());
8799 MCAuto<DataArrayInt> o2n(skin->zipCoordsTraducer());
8800 int nbOfNodesExpected(skin->getNumberOfNodes());
8801 MCAuto<DataArrayInt> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
8802 int nbCells(skin->getNumberOfCells());
8803 if(nbCells==nbOfNodesExpected)
8804 return buildUnionOf2DMeshLinear(skin,n2o);
8805 else if(2*nbCells==nbOfNodesExpected)
8806 return buildUnionOf2DMeshQuadratic(skin,n2o);
8808 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
8812 * This method makes the assumption spacedimension == meshdimension == 3.
8813 * This method works only for linear cells.
8815 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
8817 DataArrayInt *MEDCouplingUMesh::buildUnionOf3DMesh() const
8819 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8820 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
8821 MCAuto<MEDCouplingUMesh> m=computeSkin();
8822 const int *conn=m->getNodalConnectivity()->getConstPointer();
8823 const int *connI=m->getNodalConnectivityIndex()->getConstPointer();
8824 int nbOfCells=m->getNumberOfCells();
8825 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
8826 int *work=ret->getPointer(); *work++=INTERP_KERNEL::NORM_POLYHED;
8829 work=std::copy(conn+connI[0]+1,conn+connI[1],work);
8830 for(int i=1;i<nbOfCells;i++)
8833 work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
8839 * \brief Creates a graph of cell neighbors
8840 * \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
8841 * In the sky line array, graph arcs are stored in terms of (index,value) notation.
8843 * - index: 0 3 5 6 6
8844 * - value: 1 2 3 2 3 3
8845 * means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
8846 * Arcs are not doubled but reflexive (1,1) arcs are present for each cell
8848 MEDCouplingSkyLineArray *MEDCouplingUMesh::generateGraph() const
8850 checkConnectivityFullyDefined();
8852 int meshDim = this->getMeshDimension();
8853 MEDCoupling::DataArrayInt* indexr=MEDCoupling::DataArrayInt::New();
8854 MEDCoupling::DataArrayInt* revConn=MEDCoupling::DataArrayInt::New();
8855 this->getReverseNodalConnectivity(revConn,indexr);
8856 const int* indexr_ptr=indexr->getConstPointer();
8857 const int* revConn_ptr=revConn->getConstPointer();
8859 const MEDCoupling::DataArrayInt* index;
8860 const MEDCoupling::DataArrayInt* conn;
8861 conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
8862 index=this->getNodalConnectivityIndex();
8863 int nbCells=this->getNumberOfCells();
8864 const int* index_ptr=index->getConstPointer();
8865 const int* conn_ptr=conn->getConstPointer();
8867 //creating graph arcs (cell to cell relations)
8868 //arcs are stored in terms of (index,value) notation
8871 // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
8872 // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
8874 //warning here one node have less than or equal effective number of cell with it
8875 //but cell could have more than effective nodes
8876 //because other equals nodes in other domain (with other global inode)
8877 std::vector <int> cell2cell_index(nbCells+1,0);
8878 std::vector <int> cell2cell;
8879 cell2cell.reserve(3*nbCells);
8881 for (int icell=0; icell<nbCells;icell++)
8883 std::map<int,int > counter;
8884 for (int iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
8886 int inode=conn_ptr[iconn];
8887 for (int iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
8889 int icell2=revConn_ptr[iconnr];
8890 std::map<int,int>::iterator iter=counter.find(icell2);
8891 if (iter!=counter.end()) (iter->second)++;
8892 else counter.insert(std::make_pair(icell2,1));
8895 for (std::map<int,int>::const_iterator iter=counter.begin();
8896 iter!=counter.end(); iter++)
8897 if (iter->second >= meshDim)
8899 cell2cell_index[icell+1]++;
8900 cell2cell.push_back(iter->first);
8905 cell2cell_index[0]=0;
8906 for (int icell=0; icell<nbCells;icell++)
8907 cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
8909 //filling up index and value to create skylinearray structure
8910 MEDCouplingSkyLineArray* array=new MEDCouplingSkyLineArray(cell2cell_index,cell2cell);
8915 * This method put in zip format into parameter 'zipFrmt' in full interlace mode.
8916 * This format is often asked by INTERP_KERNEL algorithms to avoid many indirections into coordinates array.
8918 void MEDCouplingUMesh::FillInCompact3DMode(int spaceDim, int nbOfNodesInCell, const int *conn, const double *coo, double *zipFrmt)
8922 for(int i=0;i<nbOfNodesInCell;i++)
8923 w=std::copy(coo+3*conn[i],coo+3*conn[i]+3,w);
8924 else if(spaceDim==2)
8926 for(int i=0;i<nbOfNodesInCell;i++)
8928 w=std::copy(coo+2*conn[i],coo+2*conn[i]+2,w);
8933 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::FillInCompact3DMode : Invalid spaceDim specified : must be 2 or 3 !");
8936 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
8938 int nbOfCells=getNumberOfCells();
8940 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
8941 ofs << " <" << getVTKDataSetType() << ">\n";
8942 ofs << " <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
8943 ofs << " <PointData>\n" << pointData << std::endl;
8944 ofs << " </PointData>\n";
8945 ofs << " <CellData>\n" << cellData << std::endl;
8946 ofs << " </CellData>\n";
8947 ofs << " <Points>\n";
8948 if(getSpaceDimension()==3)
8949 _coords->writeVTK(ofs,8,"Points",byteData);
8952 MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
8953 coo->writeVTK(ofs,8,"Points",byteData);
8955 ofs << " </Points>\n";
8956 ofs << " <Cells>\n";
8957 const int *cPtr=_nodal_connec->getConstPointer();
8958 const int *cIPtr=_nodal_connec_index->getConstPointer();
8959 MCAuto<DataArrayInt> faceoffsets=DataArrayInt::New(); faceoffsets->alloc(nbOfCells,1);
8960 MCAuto<DataArrayInt> types=DataArrayInt::New(); types->alloc(nbOfCells,1);
8961 MCAuto<DataArrayInt> offsets=DataArrayInt::New(); offsets->alloc(nbOfCells,1);
8962 MCAuto<DataArrayInt> connectivity=DataArrayInt::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
8963 int *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
8964 int szFaceOffsets=0,szConn=0;
8965 for(int i=0;i<nbOfCells;i++,w1++,w2++,w3++)
8968 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
8971 *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
8972 w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
8976 int deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
8977 *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
8978 std::set<int> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
8979 *w3=szConn+(int)c.size(); szConn+=(int)c.size();
8980 w4=std::copy(c.begin(),c.end(),w4);
8983 types->transformWithIndArr(MEDCOUPLING2VTKTYPETRADUCER,MEDCOUPLING2VTKTYPETRADUCER+INTERP_KERNEL::NORM_MAXTYPE+1);
8984 types->writeVTK(ofs,8,"UInt8","types",byteData);
8985 offsets->writeVTK(ofs,8,"Int32","offsets",byteData);
8986 if(szFaceOffsets!=0)
8987 {//presence of Polyhedra
8988 connectivity->reAlloc(szConn);
8989 faceoffsets->writeVTK(ofs,8,"Int32","faceoffsets",byteData);
8990 MCAuto<DataArrayInt> faces=DataArrayInt::New(); faces->alloc(szFaceOffsets,1);
8991 w1=faces->getPointer();
8992 for(int i=0;i<nbOfCells;i++)
8993 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
8995 int nbFaces=std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1)+1;
8997 const int *w6=cPtr+cIPtr[i]+1,*w5=0;
8998 for(int j=0;j<nbFaces;j++)
9000 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
9001 *w1++=(int)std::distance(w6,w5);
9002 w1=std::copy(w6,w5,w1);
9006 faces->writeVTK(ofs,8,"Int32","faces",byteData);
9008 connectivity->writeVTK(ofs,8,"Int32","connectivity",byteData);
9009 ofs << " </Cells>\n";
9010 ofs << " </Piece>\n";
9011 ofs << " </" << getVTKDataSetType() << ">\n";
9014 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
9016 stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
9018 { stream << " Not set !"; return ; }
9019 stream << " Mesh dimension : " << _mesh_dim << ".";
9023 { stream << " No coordinates set !"; return ; }
9024 if(!_coords->isAllocated())
9025 { stream << " Coordinates set but not allocated !"; return ; }
9026 stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
9027 stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
9028 if(!_nodal_connec_index)
9029 { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
9030 if(!_nodal_connec_index->isAllocated())
9031 { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
9032 int lgth=_nodal_connec_index->getNumberOfTuples();
9033 int cpt=_nodal_connec_index->getNumberOfComponents();
9034 if(cpt!=1 || lgth<1)
9036 stream << std::endl << "Number of cells : " << lgth-1 << ".";
9039 std::string MEDCouplingUMesh::getVTKDataSetType() const
9041 return std::string("UnstructuredGrid");
9044 std::string MEDCouplingUMesh::getVTKFileExtension() const
9046 return std::string("vtu");
9050 * Partitions the first given 2D mesh using the second given 2D mesh as a tool, and
9051 * returns a result mesh constituted by polygons.
9052 * Thus the final result contains all nodes from m1 plus new nodes. However it doesn't necessarily contains
9053 * all nodes from m2.
9054 * The meshes should be in 2D space. In
9055 * addition, returns two arrays mapping cells of the result mesh to cells of the input
9057 * \param [in] m1 - the first input mesh which is a partitioned object. The mesh must be so that each point in the space covered by \a m1
9058 * must be covered exactly by one entity, \b no \b more. If it is not the case, some tools are available to heal the mesh (conformize2D, mergeNodes)
9059 * \param [in] m2 - the second input mesh which is a partition tool. The mesh must be so that each point in the space covered by \a m2
9060 * must be covered exactly by one entity, \b no \b more. If it is not the case, some tools are available to heal the mesh (conformize2D, mergeNodes)
9061 * \param [in] eps - precision used to detect coincident mesh entities.
9062 * \param [out] cellNb1 - a new instance of DataArrayInt holding for each result
9063 * cell an id of the cell of \a m1 it comes from. The caller is to delete
9064 * this array using decrRef() as it is no more needed.
9065 * \param [out] cellNb2 - a new instance of DataArrayInt holding for each result
9066 * cell an id of the cell of \a m2 it comes from. -1 value means that a
9067 * result cell comes from a cell (or part of cell) of \a m1 not overlapped by
9068 * any cell of \a m2. The caller is to delete this array using decrRef() as
9069 * it is no more needed.
9070 * \return MEDCouplingUMesh * - the result 2D mesh which is a new instance of
9071 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
9072 * is no more needed.
9073 * \throw If the coordinates array is not set in any of the meshes.
9074 * \throw If the nodal connectivity of cells is not defined in any of the meshes.
9075 * \throw If any of the meshes is not a 2D mesh in 2D space.
9077 * \sa conformize2D, mergeNodes
9079 MEDCouplingUMesh *MEDCouplingUMesh::Intersect2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2,
9080 double eps, DataArrayInt *&cellNb1, DataArrayInt *&cellNb2)
9083 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshes : input meshes must be not NULL !");
9084 m1->checkFullyDefined();
9085 m2->checkFullyDefined();
9086 if(m1->getMeshDimension()!=2 || m1->getSpaceDimension()!=2 || m2->getMeshDimension()!=2 || m2->getSpaceDimension()!=2)
9087 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshes works on umeshes m1 AND m2 with meshdim equal to 2 and spaceDim equal to 2 too!");
9089 // Step 1: compute all edge intersections (new nodes)
9090 std::vector< std::vector<int> > intersectEdge1, colinear2, subDiv2;
9091 MEDCouplingUMesh *m1Desc=0,*m2Desc=0; // descending connec. meshes
9092 DataArrayInt *desc1=0,*descIndx1=0,*revDesc1=0,*revDescIndx1=0,*desc2=0,*descIndx2=0,*revDesc2=0,*revDescIndx2=0;
9093 std::vector<double> addCoo,addCoordsQuadratic; // coordinates of newly created nodes
9094 IntersectDescending2DMeshes(m1,m2,eps,intersectEdge1,colinear2, subDiv2,
9095 m1Desc,desc1,descIndx1,revDesc1,revDescIndx1,
9096 addCoo, m2Desc,desc2,descIndx2,revDesc2,revDescIndx2);
9097 revDesc1->decrRef(); revDescIndx1->decrRef(); revDesc2->decrRef(); revDescIndx2->decrRef();
9098 MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(desc2),dd4(descIndx2);
9099 MCAuto<MEDCouplingUMesh> dd5(m1Desc),dd6(m2Desc);
9101 // Step 2: re-order newly created nodes according to the ordering found in m2
9102 std::vector< std::vector<int> > intersectEdge2;
9103 BuildIntersectEdges(m1Desc,m2Desc,addCoo,subDiv2,intersectEdge2);
9104 subDiv2.clear(); dd5=0; dd6=0;
9107 std::vector<int> cr,crI; //no DataArrayInt because interface with Geometric2D
9108 std::vector<int> cNb1,cNb2; //no DataArrayInt because interface with Geometric2D
9109 BuildIntersecting2DCellsFromEdges(eps,m1,desc1->getConstPointer(),descIndx1->getConstPointer(),intersectEdge1,colinear2,m2,desc2->getConstPointer(),descIndx2->getConstPointer(),intersectEdge2,addCoo,
9110 /* outputs -> */addCoordsQuadratic,cr,crI,cNb1,cNb2);
9112 // Step 4: Prepare final result:
9113 MCAuto<DataArrayDouble> addCooDa(DataArrayDouble::New());
9114 addCooDa->alloc((int)(addCoo.size())/2,2);
9115 std::copy(addCoo.begin(),addCoo.end(),addCooDa->getPointer());
9116 MCAuto<DataArrayDouble> addCoordsQuadraticDa(DataArrayDouble::New());
9117 addCoordsQuadraticDa->alloc((int)(addCoordsQuadratic.size())/2,2);
9118 std::copy(addCoordsQuadratic.begin(),addCoordsQuadratic.end(),addCoordsQuadraticDa->getPointer());
9119 std::vector<const DataArrayDouble *> coordss(4);
9120 coordss[0]=m1->getCoords(); coordss[1]=m2->getCoords(); coordss[2]=addCooDa; coordss[3]=addCoordsQuadraticDa;
9121 MCAuto<DataArrayDouble> coo(DataArrayDouble::Aggregate(coordss));
9122 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("Intersect2D",2));
9123 MCAuto<DataArrayInt> conn(DataArrayInt::New()); conn->alloc((int)cr.size(),1); std::copy(cr.begin(),cr.end(),conn->getPointer());
9124 MCAuto<DataArrayInt> connI(DataArrayInt::New()); connI->alloc((int)crI.size(),1); std::copy(crI.begin(),crI.end(),connI->getPointer());
9125 MCAuto<DataArrayInt> c1(DataArrayInt::New()); c1->alloc((int)cNb1.size(),1); std::copy(cNb1.begin(),cNb1.end(),c1->getPointer());
9126 MCAuto<DataArrayInt> c2(DataArrayInt::New()); c2->alloc((int)cNb2.size(),1); std::copy(cNb2.begin(),cNb2.end(),c2->getPointer());
9127 ret->setConnectivity(conn,connI,true);
9128 ret->setCoords(coo);
9129 cellNb1=c1.retn(); cellNb2=c2.retn();
9135 bool IsColinearOfACellOf(const std::vector< std::vector<int> >& intersectEdge1, const std::vector<int>& candidates, int start, int stop, int& retVal)
9137 if(candidates.empty())
9139 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
9141 const std::vector<int>& pool(intersectEdge1[*it]);
9142 int tmp[2]; tmp[0]=start; tmp[1]=stop;
9143 if(std::search(pool.begin(),pool.end(),tmp,tmp+2)!=pool.end())
9148 tmp[0]=stop; tmp[1]=start;
9149 if(std::search(pool.begin(),pool.end(),tmp,tmp+2)!=pool.end())
9158 MEDCouplingUMesh *BuildMesh1DCutFrom(const MEDCouplingUMesh *mesh1D, const std::vector< std::vector<int> >& intersectEdge2, const DataArrayDouble *coords1, const std::vector<double>& addCoo, const std::map<int,int>& mergedNodes, const std::vector< std::vector<int> >& colinear2, const std::vector< std::vector<int> >& intersectEdge1,
9159 MCAuto<DataArrayInt>& idsInRetColinear, MCAuto<DataArrayInt>& idsInMesh1DForIdsInRetColinear)
9161 idsInRetColinear=DataArrayInt::New(); idsInRetColinear->alloc(0,1);
9162 idsInMesh1DForIdsInRetColinear=DataArrayInt::New(); idsInMesh1DForIdsInRetColinear->alloc(0,1);
9163 int nCells(mesh1D->getNumberOfCells());
9164 if(nCells!=(int)intersectEdge2.size())
9165 throw INTERP_KERNEL::Exception("BuildMesh1DCutFrom : internal error # 1 !");
9166 const DataArrayDouble *coo2(mesh1D->getCoords());
9167 const int *c(mesh1D->getNodalConnectivity()->begin()),*ci(mesh1D->getNodalConnectivityIndex()->begin());
9168 const double *coo2Ptr(coo2->begin());
9169 int offset1(coords1->getNumberOfTuples());
9170 int offset2(offset1+coo2->getNumberOfTuples());
9171 int offset3(offset2+addCoo.size()/2);
9172 std::vector<double> addCooQuad;
9173 MCAuto<DataArrayInt> cOut(DataArrayInt::New()),ciOut(DataArrayInt::New()); cOut->alloc(0,1); ciOut->alloc(1,1); ciOut->setIJ(0,0,0);
9174 int tmp[4],cicnt(0),kk(0);
9175 for(int i=0;i<nCells;i++)
9177 std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
9178 INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coo2Ptr,m));
9179 const std::vector<int>& subEdges(intersectEdge2[i]);
9180 int nbSubEdge(subEdges.size()/2);
9181 for(int j=0;j<nbSubEdge;j++,kk++)
9183 MCAuto<INTERP_KERNEL::Node> n1(MEDCouplingUMeshBuildQPNode(subEdges[2*j],coords1->begin(),offset1,coo2Ptr,offset2,addCoo)),n2(MEDCouplingUMeshBuildQPNode(subEdges[2*j+1],coords1->begin(),offset1,coo2Ptr,offset2,addCoo));
9184 MCAuto<INTERP_KERNEL::Edge> e2(e->buildEdgeLyingOnMe(n1,n2));
9185 INTERP_KERNEL::Edge *e2Ptr(e2);
9186 std::map<int,int>::const_iterator itm;
9187 if(dynamic_cast<INTERP_KERNEL::EdgeArcCircle *>(e2Ptr))
9189 tmp[0]=INTERP_KERNEL::NORM_SEG3;
9190 itm=mergedNodes.find(subEdges[2*j]);
9191 tmp[1]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j];
9192 itm=mergedNodes.find(subEdges[2*j+1]);
9193 tmp[2]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j+1];
9194 tmp[3]=offset3+(int)addCooQuad.size()/2;
9196 e2->getBarycenter(tmp2); addCooQuad.insert(addCooQuad.end(),tmp2,tmp2+2);
9198 cOut->insertAtTheEnd(tmp,tmp+4);
9199 ciOut->pushBackSilent(cicnt);
9203 tmp[0]=INTERP_KERNEL::NORM_SEG2;
9204 itm=mergedNodes.find(subEdges[2*j]);
9205 tmp[1]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j];
9206 itm=mergedNodes.find(subEdges[2*j+1]);
9207 tmp[2]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j+1];
9209 cOut->insertAtTheEnd(tmp,tmp+3);
9210 ciOut->pushBackSilent(cicnt);
9213 if(IsColinearOfACellOf(intersectEdge1,colinear2[i],tmp[1],tmp[2],tmp00))
9215 idsInRetColinear->pushBackSilent(kk);
9216 idsInMesh1DForIdsInRetColinear->pushBackSilent(tmp00);
9221 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(mesh1D->getName(),1));
9222 ret->setConnectivity(cOut,ciOut,true);
9223 MCAuto<DataArrayDouble> arr3(DataArrayDouble::New());
9224 arr3->useArray(&addCoo[0],false,C_DEALLOC,(int)addCoo.size()/2,2);
9225 MCAuto<DataArrayDouble> arr4(DataArrayDouble::New()); arr4->useArray(&addCooQuad[0],false,C_DEALLOC,(int)addCooQuad.size()/2,2);
9226 std::vector<const DataArrayDouble *> coordss(4);
9227 coordss[0]=coords1; coordss[1]=mesh1D->getCoords(); coordss[2]=arr3; coordss[3]=arr4;
9228 MCAuto<DataArrayDouble> arr(DataArrayDouble::Aggregate(coordss));
9229 ret->setCoords(arr);
9233 MEDCouplingUMesh *BuildRefined2DCellLinear(const DataArrayDouble *coords, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9235 std::vector<int> allEdges;
9236 for(const int *it2(descBg);it2!=descEnd;it2++)
9238 const std::vector<int>& edge1(intersectEdge1[std::abs(*it2)-1]);
9240 allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9242 allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9244 std::size_t nb(allEdges.size());
9246 throw INTERP_KERNEL::Exception("BuildRefined2DCellLinear : internal error 1 !");
9247 std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9248 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
9249 ret->setCoords(coords);
9250 ret->allocateCells(1);
9251 std::vector<int> connOut(nbOfEdgesOf2DCellSplit);
9252 for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9253 connOut[kk]=allEdges[2*kk];
9254 ret->insertNextCell(INTERP_KERNEL::NORM_POLYGON,connOut.size(),&connOut[0]);
9258 MEDCouplingUMesh *BuildRefined2DCellQuadratic(const DataArrayDouble *coords, const MEDCouplingUMesh *mesh2D, int cellIdInMesh2D, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9260 const int *c(mesh2D->getNodalConnectivity()->begin()),*ci(mesh2D->getNodalConnectivityIndex()->begin());
9261 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[cellIdInMesh2D]]));
9263 unsigned sz(cm.getNumberOfSons2(c+ci[cellIdInMesh2D]+1,ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]-1));
9264 if(sz!=std::distance(descBg,descEnd))
9265 throw INTERP_KERNEL::Exception("BuildRefined2DCellQuadratic : internal error 1 !");
9266 INTERP_KERNEL::AutoPtr<int> tmpPtr(new int[ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]]);
9267 std::vector<int> allEdges,centers;
9268 const double *coordsPtr(coords->begin());
9269 MCAuto<DataArrayDouble> addCoo(DataArrayDouble::New()); addCoo->alloc(0,1);
9270 int offset(coords->getNumberOfTuples());
9271 for(const int *it2(descBg);it2!=descEnd;it2++,ii++)
9273 INTERP_KERNEL::NormalizedCellType typeOfSon;
9274 cm.fillSonCellNodalConnectivity2(ii,c+ci[cellIdInMesh2D]+1,ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]-1,tmpPtr,typeOfSon);
9275 const std::vector<int>& edge1(intersectEdge1[std::abs(*it2)-1]);
9277 allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9279 allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9281 centers.push_back(tmpPtr[2]);//special case where no subsplit of edge -> reuse the original center.
9283 {//the current edge has been subsplit -> create corresponding centers.
9284 std::size_t nbOfCentersToAppend(edge1.size()/2);
9285 std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9286 MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpPtr,coordsPtr,m));
9287 std::vector<int>::const_iterator it3(allEdges.end()-edge1.size());
9288 for(std::size_t k=0;k<nbOfCentersToAppend;k++)
9291 const double *aa(coordsPtr+2*(*it3++));
9292 const double *bb(coordsPtr+2*(*it3++));
9293 ee->getMiddleOfPoints(aa,bb,tmpp);
9294 addCoo->insertAtTheEnd(tmpp,tmpp+2);
9295 centers.push_back(offset+k);
9299 std::size_t nb(allEdges.size());
9301 throw INTERP_KERNEL::Exception("BuildRefined2DCellQuadratic : internal error 2 !");
9302 std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9303 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
9305 ret->setCoords(coords);
9308 addCoo->rearrange(2);
9309 addCoo=DataArrayDouble::Aggregate(coords,addCoo);
9310 ret->setCoords(addCoo);
9312 ret->allocateCells(1);
9313 std::vector<int> connOut(nbOfEdgesOf2DCellSplit);
9314 for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9315 connOut[kk]=allEdges[2*kk];
9316 connOut.insert(connOut.end(),centers.begin(),centers.end());
9317 ret->insertNextCell(INTERP_KERNEL::NORM_QPOLYG,connOut.size(),&connOut[0]);
9322 * This method creates a refinement of a cell in \a mesh2D. Those cell is defined by descending connectivity and the sorted subdivided nodal connectivity
9325 * \param [in] mesh2D - The origin 2D mesh. \b Warning \b coords are not those of \a mesh2D. But mesh2D->getCoords()==coords[:mesh2D->getNumberOfNodes()]
9327 MEDCouplingUMesh *BuildRefined2DCell(const DataArrayDouble *coords, const MEDCouplingUMesh *mesh2D, int cellIdInMesh2D, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9329 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(mesh2D->getTypeOfCell(cellIdInMesh2D)));
9330 if(!cm.isQuadratic())
9331 return BuildRefined2DCellLinear(coords,descBg,descEnd,intersectEdge1);
9333 return BuildRefined2DCellQuadratic(coords,mesh2D,cellIdInMesh2D,descBg,descEnd,intersectEdge1);
9336 void AddCellInMesh2D(MEDCouplingUMesh *mesh2D, const std::vector<int>& conn, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edges)
9339 for(std::vector< MCAuto<INTERP_KERNEL::Edge> >::const_iterator it=edges.begin();it!=edges.end();it++)
9341 const INTERP_KERNEL::Edge *ee(*it);
9342 if(dynamic_cast<const INTERP_KERNEL::EdgeArcCircle *>(ee))
9346 mesh2D->insertNextCell(INTERP_KERNEL::NORM_POLYGON,conn.size(),&conn[0]);
9349 const double *coo(mesh2D->getCoords()->begin());
9350 std::size_t sz(conn.size());
9351 std::vector<double> addCoo;
9352 std::vector<int> conn2(conn);
9353 int offset(mesh2D->getNumberOfNodes());
9354 for(std::size_t i=0;i<sz;i++)
9357 edges[(i+1)%sz]->getMiddleOfPoints(coo+2*conn[i],coo+2*conn[(i+1)%sz],tmp);// tony a chier i+1 -> i
9358 addCoo.insert(addCoo.end(),tmp,tmp+2);
9359 conn2.push_back(offset+(int)i);
9361 mesh2D->getCoords()->rearrange(1);
9362 mesh2D->getCoords()->pushBackValsSilent(&addCoo[0],&addCoo[0]+addCoo.size());
9363 mesh2D->getCoords()->rearrange(2);
9364 mesh2D->insertNextCell(INTERP_KERNEL::NORM_QPOLYG,conn2.size(),&conn2[0]);
9369 * \b WARNING edges in out1 coming from \a splitMesh1D are \b NOT oriented because only used for equation of curve.
9371 * This method cuts in 2 parts the input 2D cell given using boundaries description (\a edge1Bis and \a edge1BisPtr) using
9372 * a set of edges defined in \a splitMesh1D.
9374 void BuildMesh2DCutInternal2(const MEDCouplingUMesh *splitMesh1D, const std::vector<int>& edge1Bis, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edge1BisPtr,
9375 std::vector< std::vector<int> >& out0, std::vector< std::vector< MCAuto<INTERP_KERNEL::Edge> > >& out1)
9377 std::size_t nb(edge1Bis.size()/2);
9378 std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9379 int iEnd(splitMesh1D->getNumberOfCells());
9381 throw INTERP_KERNEL::Exception("BuildMesh2DCutInternal2 : internal error ! input 1D mesh must have at least one cell !");
9383 const int *cSplitPtr(splitMesh1D->getNodalConnectivity()->begin()),*ciSplitPtr(splitMesh1D->getNodalConnectivityIndex()->begin());
9384 for(ii=0;ii<nb && edge1Bis[2*ii]!=cSplitPtr[ciSplitPtr[0]+1];ii++);
9385 for(jj=ii;jj<nb && edge1Bis[2*jj+1]!=cSplitPtr[ciSplitPtr[iEnd-1]+2];jj++);
9388 {//the edges splitMesh1D[iStart:iEnd] does not fully cut the current 2D cell -> single output cell
9389 out0.resize(1); out1.resize(1);
9390 std::vector<int>& connOut(out0[0]);
9391 connOut.resize(nbOfEdgesOf2DCellSplit);
9392 std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr(out1[0]);
9393 edgesPtr.resize(nbOfEdgesOf2DCellSplit);
9394 for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9396 connOut[kk]=edge1Bis[2*kk];
9397 edgesPtr[kk]=edge1BisPtr[2*kk];
9402 // [i,iEnd[ contains the
9403 out0.resize(2); out1.resize(2);
9404 std::vector<int>& connOutLeft(out0[0]);
9405 std::vector<int>& connOutRight(out0[1]);//connOutLeft should end with edge1Bis[2*ii] and connOutRight should end with edge1Bis[2*jj+1]
9406 std::vector< MCAuto<INTERP_KERNEL::Edge> >& eleft(out1[0]);
9407 std::vector< MCAuto<INTERP_KERNEL::Edge> >& eright(out1[1]);
9408 for(std::size_t k=ii;k<jj+1;k++)
9409 { connOutLeft.push_back(edge1Bis[2*k+1]); eleft.push_back(edge1BisPtr[2*k+1]); }
9410 std::vector< MCAuto<INTERP_KERNEL::Edge> > ees(iEnd);
9411 for(int ik=0;ik<iEnd;ik++)
9413 std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9414 MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)cSplitPtr[ciSplitPtr[ik]],cSplitPtr+ciSplitPtr[ik]+1,splitMesh1D->getCoords()->begin(),m));
9417 for(int ik=iEnd-1;ik>=0;ik--)
9418 connOutLeft.push_back(cSplitPtr[ciSplitPtr[ik]+1]);
9419 for(std::size_t k=jj+1;k<nbOfEdgesOf2DCellSplit+ii;k++)
9420 { connOutRight.push_back(edge1Bis[2*k+1]); eright.push_back(edge1BisPtr[2*k+1]); }
9421 eleft.insert(eleft.end(),ees.rbegin(),ees.rend());
9422 for(int ik=0;ik<iEnd;ik++)
9423 connOutRight.push_back(cSplitPtr[ciSplitPtr[ik]+2]);
9424 eright.insert(eright.end(),ees.begin(),ees.end());
9436 CellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr);
9438 std::vector<int> _edges;
9439 std::vector< MCAuto<INTERP_KERNEL::Edge> > _edges_ptr;
9442 CellInfo::CellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr)
9444 std::size_t nbe(edges.size());
9445 std::vector<int> edges2(2*nbe); std::vector< MCAuto<INTERP_KERNEL::Edge> > edgesPtr2(2*nbe);
9446 for(std::size_t i=0;i<nbe;i++)
9448 edges2[2*i]=edges[i]; edges2[2*i+1]=edges[(i+1)%nbe];
9449 edgesPtr2[2*i]=edgesPtr[(i+1)%nbe]; edgesPtr2[2*i+1]=edgesPtr[(i+1)%nbe];//tony a chier
9451 _edges.resize(4*nbe); _edges_ptr.resize(4*nbe);
9452 std::copy(edges2.begin(),edges2.end(),_edges.begin()); std::copy(edges2.begin(),edges2.end(),_edges.begin()+2*nbe);
9453 std::copy(edgesPtr2.begin(),edgesPtr2.end(),_edges_ptr.begin()); std::copy(edgesPtr2.begin(),edgesPtr2.end(),_edges_ptr.begin()+2*nbe);
9459 EdgeInfo(int istart, int iend, const MCAuto<MEDCouplingUMesh>& mesh):_istart(istart),_iend(iend),_mesh(mesh),_left(-7),_right(-7) { }
9460 EdgeInfo(int istart, int iend, int pos, const MCAuto<INTERP_KERNEL::Edge>& edge):_istart(istart),_iend(iend),_edge(edge),_left(pos),_right(pos+1) { }
9461 bool isInMyRange(int pos) const { return pos>=_istart && pos<_iend; }
9462 void somethingHappendAt(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight);
9463 void feedEdgeInfoAt(double eps, const MEDCouplingUMesh *mesh2D, int offset, int neighbors[2]) const;
9467 MCAuto<MEDCouplingUMesh> _mesh;
9468 MCAuto<INTERP_KERNEL::Edge> _edge;
9473 void EdgeInfo::somethingHappendAt(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight)
9475 const MEDCouplingUMesh *mesh(_mesh);
9481 { _left++; _right++; return ; }
9484 bool isLeft(std::find(newLeft.begin(),newLeft.end(),_edge)!=newLeft.end()),isRight(std::find(newRight.begin(),newRight.end(),_edge)!=newRight.end());
9485 if((isLeft && isRight) || (!isLeft && !isRight))
9486 throw INTERP_KERNEL::Exception("EdgeInfo::somethingHappendAt : internal error # 1 !");
9497 bool isLeft(std::find(newLeft.begin(),newLeft.end(),_edge)!=newLeft.end()),isRight(std::find(newRight.begin(),newRight.end(),_edge)!=newRight.end());
9498 if((isLeft && isRight) || (!isLeft && !isRight))
9499 throw INTERP_KERNEL::Exception("EdgeInfo::somethingHappendAt : internal error # 2 !");
9514 void EdgeInfo::feedEdgeInfoAt(double eps, const MEDCouplingUMesh *mesh2D, int offset, int neighbors[2]) const
9516 const MEDCouplingUMesh *mesh(_mesh);
9519 neighbors[0]=offset+_left; neighbors[1]=offset+_right;
9522 {// not fully splitting cell case
9523 if(mesh2D->getNumberOfCells()==1)
9524 {//little optimization. 1 cell no need to find in which cell mesh is !
9525 neighbors[0]=offset; neighbors[1]=offset;
9530 MCAuto<DataArrayDouble> barys(mesh->computeCellCenterOfMass());
9531 int cellId(mesh2D->getCellContainingPoint(barys->begin(),eps));
9533 throw INTERP_KERNEL::Exception("EdgeInfo::feedEdgeInfoAt : internal error !");
9534 neighbors[0]=offset+cellId; neighbors[1]=offset+cellId;
9539 class VectorOfCellInfo
9542 VectorOfCellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr);
9543 std::size_t size() const { return _pool.size(); }
9544 int getPositionOf(double eps, const MEDCouplingUMesh *mesh) const;
9545 void setMeshAt(int pos, const MCAuto<MEDCouplingUMesh>& mesh, int istart, int iend, const MCAuto<MEDCouplingUMesh>& mesh1DInCase, const std::vector< std::vector<int> >& edges, const std::vector< std::vector< MCAuto<INTERP_KERNEL::Edge> > >& edgePtrs);
9546 const std::vector<int>& getConnOf(int pos) const { return get(pos)._edges; }
9547 const std::vector< MCAuto<INTERP_KERNEL::Edge> >& getEdgePtrOf(int pos) const { return get(pos)._edges_ptr; }
9548 MCAuto<MEDCouplingUMesh> getZeMesh() const { return _ze_mesh; }
9549 void feedEdgeInfoAt(double eps, int pos, int offset, int neighbors[2]) const;
9551 int getZePosOfEdgeGivenItsGlobalId(int pos) const;
9552 void updateEdgeInfo(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight);
9553 const CellInfo& get(int pos) const;
9554 CellInfo& get(int pos);
9556 std::vector<CellInfo> _pool;
9557 MCAuto<MEDCouplingUMesh> _ze_mesh;
9558 std::vector<EdgeInfo> _edge_info;
9561 VectorOfCellInfo::VectorOfCellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr):_pool(1)
9563 _pool[0]._edges=edges;
9564 _pool[0]._edges_ptr=edgesPtr;
9567 int VectorOfCellInfo::getPositionOf(double eps, const MEDCouplingUMesh *mesh) const
9570 throw INTERP_KERNEL::Exception("VectorOfCellSplitter::getPositionOf : empty !");
9573 const MEDCouplingUMesh *zeMesh(_ze_mesh);
9575 throw INTERP_KERNEL::Exception("VectorOfCellSplitter::getPositionOf : null aggregated mesh !");
9576 MCAuto<DataArrayDouble> barys(mesh->computeCellCenterOfMass());
9577 return zeMesh->getCellContainingPoint(barys->begin(),eps);
9580 void VectorOfCellInfo::setMeshAt(int pos, const MCAuto<MEDCouplingUMesh>& mesh, int istart, int iend, const MCAuto<MEDCouplingUMesh>& mesh1DInCase, const std::vector< std::vector<int> >& edges, const std::vector< std::vector< MCAuto<INTERP_KERNEL::Edge> > >& edgePtrs)
9582 get(pos);//to check pos
9583 bool isFast(pos==0 && _pool.size()==1);
9584 std::size_t sz(edges.size());
9585 // dealing with edges
9587 _edge_info.push_back(EdgeInfo(istart,iend,mesh1DInCase));
9589 _edge_info.push_back(EdgeInfo(istart,iend,pos,edgePtrs[0].back()));
9591 std::vector<CellInfo> pool(_pool.size()-1+sz);
9592 for(int i=0;i<pos;i++)
9594 for(std::size_t j=0;j<sz;j++)
9595 pool[pos+j]=CellInfo(edges[j],edgePtrs[j]);
9596 for(int i=pos+1;i<(int)_pool.size();i++)
9597 pool[i+sz-1]=_pool[i];
9601 updateEdgeInfo(pos,edgePtrs[0],edgePtrs[1]);
9609 std::vector< MCAuto<MEDCouplingUMesh> > ms;
9612 MCAuto<MEDCouplingUMesh> elt(static_cast<MEDCouplingUMesh *>(_ze_mesh->buildPartOfMySelfSlice(0,pos,true)));
9616 if(pos<_ze_mesh->getNumberOfCells()-1)
9618 MCAuto<MEDCouplingUMesh> elt(static_cast<MEDCouplingUMesh *>(_ze_mesh->buildPartOfMySelfSlice(pos+1,_ze_mesh->getNumberOfCells(),true)));
9621 std::vector< const MEDCouplingUMesh *> ms2(ms.size());
9622 for(std::size_t j=0;j<ms2.size();j++)
9624 _ze_mesh=MEDCouplingUMesh::MergeUMeshesOnSameCoords(ms2);
9627 void VectorOfCellInfo::feedEdgeInfoAt(double eps, int pos, int offset, int neighbors[2]) const
9629 _edge_info[getZePosOfEdgeGivenItsGlobalId(pos)].feedEdgeInfoAt(eps,_ze_mesh,offset,neighbors);
9632 int VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId(int pos) const
9635 throw INTERP_KERNEL::Exception("VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId : invalid id ! Must be >=0 !");
9637 for(std::vector<EdgeInfo>::const_iterator it=_edge_info.begin();it!=_edge_info.end();it++,ret++)
9639 if((*it).isInMyRange(pos))
9642 throw INTERP_KERNEL::Exception("VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId : invalid id !");
9645 void VectorOfCellInfo::updateEdgeInfo(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight)
9647 get(pos);//to check;
9648 if(_edge_info.empty())
9650 std::size_t sz(_edge_info.size()-1);
9651 for(std::size_t i=0;i<sz;i++)
9652 _edge_info[i].somethingHappendAt(pos,newLeft,newRight);
9655 const CellInfo& VectorOfCellInfo::get(int pos) const
9657 if(pos<0 || pos>=(int)_pool.size())
9658 throw INTERP_KERNEL::Exception("VectorOfCellSplitter::get const : invalid pos !");
9662 CellInfo& VectorOfCellInfo::get(int pos)
9664 if(pos<0 || pos>=(int)_pool.size())
9665 throw INTERP_KERNEL::Exception("VectorOfCellSplitter::get : invalid pos !");
9671 * - a \b closed set of edges ( \a allEdges and \a allEdgesPtr ) that defines the split descending 2D cell.
9672 * - \a splitMesh1D a split 2D curve mesh contained into 2D cell defined above.
9674 * This method returns the 2D mesh and feeds \a idsLeftRight using offset.
9676 * Algorithm : \a splitMesh1D is cut into contiguous parts. Each contiguous parts will build incrementally the output 2D cells.
9678 * \param [in] allEdges a list of pairs (beginNode, endNode). Linked with \a allEdgesPtr to get the equation of edge.
9680 MEDCouplingUMesh *BuildMesh2DCutInternal(double eps, const MEDCouplingUMesh *splitMesh1D, const std::vector<int>& allEdges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& allEdgesPtr, int offset,
9681 MCAuto<DataArrayInt>& idsLeftRight)
9683 int nbCellsInSplitMesh1D(splitMesh1D->getNumberOfCells());
9684 if(nbCellsInSplitMesh1D==0)
9685 throw INTERP_KERNEL::Exception("BuildMesh2DCutInternal : internal error ! input 1D mesh must have at least one cell !");
9686 const int *cSplitPtr(splitMesh1D->getNodalConnectivity()->begin()),*ciSplitPtr(splitMesh1D->getNodalConnectivityIndex()->begin());
9687 std::size_t nb(allEdges.size()),jj;
9689 throw INTERP_KERNEL::Exception("BuildMesh2DCutFrom : internal error 2 !");
9690 std::vector<int> edge1Bis(nb*2);
9691 std::vector< MCAuto<INTERP_KERNEL::Edge> > edge1BisPtr(nb*2);
9692 std::copy(allEdges.begin(),allEdges.end(),edge1Bis.begin());
9693 std::copy(allEdges.begin(),allEdges.end(),edge1Bis.begin()+nb);
9694 std::copy(allEdgesPtr.begin(),allEdgesPtr.end(),edge1BisPtr.begin());
9695 std::copy(allEdgesPtr.begin(),allEdgesPtr.end(),edge1BisPtr.begin()+nb);
9697 idsLeftRight=DataArrayInt::New(); idsLeftRight->alloc(nbCellsInSplitMesh1D*2); idsLeftRight->fillWithValue(-2); idsLeftRight->rearrange(2);
9698 int *idsLeftRightPtr(idsLeftRight->getPointer());
9699 VectorOfCellInfo pool(edge1Bis,edge1BisPtr);
9700 for(int iStart=0;iStart<nbCellsInSplitMesh1D;)
9701 {// split [0:nbCellsInSplitMesh1D) in contiguous parts [iStart:iEnd)
9703 for(;iEnd<nbCellsInSplitMesh1D;)
9705 for(jj=0;jj<nb && edge1Bis[2*jj+1]!=cSplitPtr[ciSplitPtr[iEnd]+2];jj++);
9711 if(iEnd<nbCellsInSplitMesh1D)
9714 MCAuto<MEDCouplingUMesh> partOfSplitMesh1D(static_cast<MEDCouplingUMesh *>(splitMesh1D->buildPartOfMySelfSlice(iStart,iEnd,1,true)));
9715 int pos(pool.getPositionOf(eps,partOfSplitMesh1D));
9717 MCAuto<MEDCouplingUMesh>retTmp(MEDCouplingUMesh::New("",2));
9718 retTmp->setCoords(splitMesh1D->getCoords());
9719 retTmp->allocateCells();
9721 std::vector< std::vector<int> > out0;
9722 std::vector< std::vector< MCAuto<INTERP_KERNEL::Edge> > > out1;
9724 BuildMesh2DCutInternal2(partOfSplitMesh1D,pool.getConnOf(pos),pool.getEdgePtrOf(pos),out0,out1);
9725 for(std::size_t cnt=0;cnt<out0.size();cnt++)
9726 AddCellInMesh2D(retTmp,out0[cnt],out1[cnt]);
9727 pool.setMeshAt(pos,retTmp,iStart,iEnd,partOfSplitMesh1D,out0,out1);
9731 for(int mm=0;mm<nbCellsInSplitMesh1D;mm++)
9732 pool.feedEdgeInfoAt(eps,mm,offset,idsLeftRightPtr+2*mm);
9733 return pool.getZeMesh().retn();
9736 MEDCouplingUMesh *BuildMesh2DCutFrom(double eps, int cellIdInMesh2D, const MEDCouplingUMesh *mesh2DDesc, const MEDCouplingUMesh *splitMesh1D,
9737 const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1, int offset,
9738 MCAuto<DataArrayInt>& idsLeftRight)
9740 const int *cdescPtr(mesh2DDesc->getNodalConnectivity()->begin()),*cidescPtr(mesh2DDesc->getNodalConnectivityIndex()->begin());
9742 std::vector<int> allEdges;
9743 std::vector< MCAuto<INTERP_KERNEL::Edge> > allEdgesPtr; // for each sub edge in splitMesh2D the uncut Edge object of the original mesh2D
9744 for(const int *it(descBg);it!=descEnd;it++) // for all edges in the descending connectivity of the 2D mesh in relative Fortran mode
9746 int edgeId(std::abs(*it)-1);
9747 std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9748 MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)cdescPtr[cidescPtr[edgeId]],cdescPtr+cidescPtr[edgeId]+1,mesh2DDesc->getCoords()->begin(),m));
9749 const std::vector<int>& edge1(intersectEdge1[edgeId]);
9751 allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9753 allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9754 std::size_t sz(edge1.size());
9755 for(std::size_t cnt=0;cnt<sz;cnt++)
9756 allEdgesPtr.push_back(ee);
9759 return BuildMesh2DCutInternal(eps,splitMesh1D,allEdges,allEdgesPtr,offset,idsLeftRight);
9762 bool AreEdgeEqual(const double *coo2D, const INTERP_KERNEL::CellModel& typ1, const int *conn1, const INTERP_KERNEL::CellModel& typ2, const int *conn2, double eps)
9764 if(!typ1.isQuadratic() && !typ2.isQuadratic())
9765 {//easy case comparison not
9766 return conn1[0]==conn2[0] && conn1[1]==conn2[1];
9768 else if(typ1.isQuadratic() && typ2.isQuadratic())
9770 bool status0(conn1[0]==conn2[0] && conn1[1]==conn2[1]);
9773 if(conn1[2]==conn2[2])
9775 const double *a(coo2D+2*conn1[2]),*b(coo2D+2*conn2[2]);
9776 double dist(sqrt((a[0]-b[0])*(a[0]-b[0])+(a[1]-b[1])*(a[1]-b[1])));
9780 {//only one is quadratic
9781 bool status0(conn1[0]==conn2[0] && conn1[1]==conn2[1]);
9784 const double *a(0),*bb(0),*be(0);
9785 if(typ1.isQuadratic())
9787 a=coo2D+2*conn1[2]; bb=coo2D+2*conn2[0]; be=coo2D+2*conn2[1];
9791 a=coo2D+2*conn2[2]; bb=coo2D+2*conn1[0]; be=coo2D+2*conn1[1];
9793 double b[2]; b[0]=(be[0]+bb[0])/2.; b[1]=(be[1]+bb[1])/2.;
9794 double dist(sqrt((a[0]-b[0])*(a[0]-b[0])+(a[1]-b[1])*(a[1]-b[1])));
9800 * This method returns among the cellIds [ \a candidatesIn2DBg , \a candidatesIn2DEnd ) in \a mesh2DSplit those exactly sharing \a cellIdInMesh1DSplitRelative in \a mesh1DSplit.
9801 * \a mesh2DSplit and \a mesh1DSplit are expected to share the coordinates array.
9803 * \param [in] cellIdInMesh1DSplitRelative is in Fortran mode using sign to specify direction.
9805 int FindRightCandidateAmong(const MEDCouplingUMesh *mesh2DSplit, const int *candidatesIn2DBg, const int *candidatesIn2DEnd, const MEDCouplingUMesh *mesh1DSplit, int cellIdInMesh1DSplitRelative, double eps)
9807 if(candidatesIn2DEnd==candidatesIn2DBg)
9808 throw INTERP_KERNEL::Exception("FindRightCandidateAmong : internal error 1 !");
9809 const double *coo(mesh2DSplit->getCoords()->begin());
9810 if(std::distance(candidatesIn2DBg,candidatesIn2DEnd)==1)
9811 return *candidatesIn2DBg;
9812 int edgeId(std::abs(cellIdInMesh1DSplitRelative)-1);
9813 MCAuto<MEDCouplingUMesh> cur1D(static_cast<MEDCouplingUMesh *>(mesh1DSplit->buildPartOfMySelf(&edgeId,&edgeId+1,true)));
9814 if(cellIdInMesh1DSplitRelative<0)
9815 cur1D->changeOrientationOfCells();
9816 const int *c1D(cur1D->getNodalConnectivity()->begin());
9817 const INTERP_KERNEL::CellModel& ref1DType(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c1D[0]));
9818 for(const int *it=candidatesIn2DBg;it!=candidatesIn2DEnd;it++)
9820 MCAuto<MEDCouplingUMesh> cur2D(static_cast<MEDCouplingUMesh *>(mesh2DSplit->buildPartOfMySelf(it,it+1,true)));
9821 const int *c(cur2D->getNodalConnectivity()->begin()),*ci(cur2D->getNodalConnectivityIndex()->begin());
9822 const INTERP_KERNEL::CellModel &cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[0]]));
9823 unsigned sz(cm.getNumberOfSons2(c+ci[0]+1,ci[1]-ci[0]-1));
9824 INTERP_KERNEL::AutoPtr<int> tmpPtr(new int[ci[1]-ci[0]]);
9825 for(unsigned it2=0;it2<sz;it2++)
9827 INTERP_KERNEL::NormalizedCellType typeOfSon;
9828 cm.fillSonCellNodalConnectivity2(it2,c+ci[0]+1,ci[1]-ci[0]-1,tmpPtr,typeOfSon);
9829 const INTERP_KERNEL::CellModel &curCM(INTERP_KERNEL::CellModel::GetCellModel(typeOfSon));
9830 if(AreEdgeEqual(coo,ref1DType,c1D+1,curCM,tmpPtr,eps))
9834 throw INTERP_KERNEL::Exception("FindRightCandidateAmong : internal error 2 ! Unable to find the edge among split cell !");
9840 * Partitions the first given 2D mesh using the second given 1D mesh as a tool.
9841 * Thus the final result contains the aggregation of nodes of \a mesh2D, then nodes of \a mesh1D, then new nodes that are the result of the intersection
9842 * and finaly, in case of quadratic polygon the centers of edges new nodes.
9843 * The meshes should be in 2D space. In addition, returns two arrays mapping cells of the resulting mesh to cells of the input.
9845 * \param [in] mesh2D - the 2D mesh (spacedim=meshdim=2) to be intersected using \a mesh1D tool. The mesh must be so that each point in the space covered by \a mesh2D
9846 * must be covered exactly by one entity, \b no \b more. If it is not the case, some tools are available to heal the mesh (conformize2D, mergeNodes)
9847 * \param [in] mesh1D - the 1D mesh (spacedim=2 meshdim=1) the is the tool that will be used to intersect \a mesh2D. \a mesh1D must be ordered consecutively. If it is not the case
9848 * you can invoke orderConsecutiveCells1D on \a mesh1D.
9849 * \param [in] eps - precision used to perform intersections and localization operations.
9850 * \param [out] splitMesh2D - the result of the split of \a mesh2D mesh.
9851 * \param [out] splitMesh1D - the result of the split of \a mesh1D mesh.
9852 * \param [out] cellIdInMesh2D - the array that gives for each cell id \a i in \a splitMesh2D the id in \a mesh2D it comes from.
9853 * So this array has a number of tuples equal to the number of cells of \a splitMesh2D and a number of component equal to 1.
9854 * \param [out] cellIdInMesh1D - the array of pair that gives for each cell id \a i in \a splitMesh1D the cell in \a splitMesh2D on the left for the 1st component
9855 * and the cell in \a splitMesh2D on the right for the 2nt component. -1 means no cell.
9856 * So this array has a number of tuples equal to the number of cells of \a splitMesh1D and a number of components equal to 2.
9858 * \sa Intersect2DMeshes, orderConsecutiveCells1D, conformize2D, mergeNodes
9860 void MEDCouplingUMesh::Intersect2DMeshWith1DLine(const MEDCouplingUMesh *mesh2D, const MEDCouplingUMesh *mesh1D, double eps, MEDCouplingUMesh *&splitMesh2D, MEDCouplingUMesh *&splitMesh1D, DataArrayInt *&cellIdInMesh2D, DataArrayInt *&cellIdInMesh1D)
9862 if(!mesh2D || !mesh1D)
9863 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshWith1DLine : input meshes must be not NULL !");
9864 mesh2D->checkFullyDefined();
9865 mesh1D->checkFullyDefined();
9866 const std::vector<std::string>& compNames(mesh2D->getCoords()->getInfoOnComponents());
9867 if(mesh2D->getMeshDimension()!=2 || mesh2D->getSpaceDimension()!=2 || mesh1D->getMeshDimension()!=1 || mesh1D->getSpaceDimension()!=2)
9868 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshWith1DLine works with mesh2D with spacedim=meshdim=2 and mesh1D with meshdim=1 spaceDim=2 !");
9869 // Step 1: compute all edge intersections (new nodes)
9870 std::vector< std::vector<int> > intersectEdge1, colinear2, subDiv2;
9871 std::vector<double> addCoo,addCoordsQuadratic; // coordinates of newly created nodes
9872 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
9873 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
9875 // Build desc connectivity
9876 DataArrayInt *desc1(DataArrayInt::New()),*descIndx1(DataArrayInt::New()),*revDesc1(DataArrayInt::New()),*revDescIndx1(DataArrayInt::New());
9877 MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(revDesc1),dd4(revDescIndx1);
9878 MCAuto<MEDCouplingUMesh> m1Desc(mesh2D->buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1));
9879 std::map<int,int> mergedNodes;
9880 Intersect1DMeshes(m1Desc,mesh1D,eps,intersectEdge1,colinear2,subDiv2,addCoo,mergedNodes);
9881 // use mergeNodes to fix intersectEdge1
9882 for(std::vector< std::vector<int> >::iterator it0=intersectEdge1.begin();it0!=intersectEdge1.end();it0++)
9884 std::size_t n((*it0).size()/2);
9885 int eltStart((*it0)[0]),eltEnd((*it0)[2*n-1]);
9886 std::map<int,int>::const_iterator it1;
9887 it1=mergedNodes.find(eltStart);
9888 if(it1!=mergedNodes.end())
9889 (*it0)[0]=(*it1).second;
9890 it1=mergedNodes.find(eltEnd);
9891 if(it1!=mergedNodes.end())
9892 (*it0)[2*n-1]=(*it1).second;
9895 MCAuto<DataArrayDouble> addCooDa(DataArrayDouble::New());
9896 addCooDa->useArray(&addCoo[0],false,C_DEALLOC,(int)addCoo.size()/2,2);
9897 // Step 2: re-order newly created nodes according to the ordering found in m2
9898 std::vector< std::vector<int> > intersectEdge2;
9899 BuildIntersectEdges(m1Desc,mesh1D,addCoo,subDiv2,intersectEdge2);
9901 // Step 3: compute splitMesh1D
9902 MCAuto<DataArrayInt> idsInRet1Colinear,idsInDescMesh2DForIdsInRetColinear;
9903 MCAuto<DataArrayInt> ret2(DataArrayInt::New()); ret2->alloc(0,1);
9904 MCAuto<MEDCouplingUMesh> ret1(BuildMesh1DCutFrom(mesh1D,intersectEdge2,mesh2D->getCoords(),addCoo,mergedNodes,colinear2,intersectEdge1,
9905 idsInRet1Colinear,idsInDescMesh2DForIdsInRetColinear));
9906 MCAuto<DataArrayInt> ret3(DataArrayInt::New()); ret3->alloc(ret1->getNumberOfCells()*2,1); ret3->fillWithValue(std::numeric_limits<int>::max()); ret3->rearrange(2);
9907 MCAuto<DataArrayInt> idsInRet1NotColinear(idsInRet1Colinear->buildComplement(ret1->getNumberOfCells()));
9908 // deal with cells in mesh2D that are not cut but only some of their edges are
9909 MCAuto<DataArrayInt> idsInDesc2DToBeRefined(idsInDescMesh2DForIdsInRetColinear->deepCopy());
9910 idsInDesc2DToBeRefined->abs(); idsInDesc2DToBeRefined->applyLin(1,-1);
9911 idsInDesc2DToBeRefined=idsInDesc2DToBeRefined->buildUnique();
9912 MCAuto<DataArrayInt> out0s;//ids in mesh2D that are impacted by the fact that some edges of \a mesh1D are part of the edges of those cells
9913 if(!idsInDesc2DToBeRefined->empty())
9915 DataArrayInt *out0(0),*outi0(0);
9916 MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
9917 MCAuto<DataArrayInt> outi0s(outi0);
9919 out0s=out0s->buildUnique();
9923 MCAuto<MEDCouplingUMesh> ret1NonCol(static_cast<MEDCouplingUMesh *>(ret1->buildPartOfMySelf(idsInRet1NotColinear->begin(),idsInRet1NotColinear->end())));
9924 MCAuto<DataArrayDouble> baryRet1(ret1NonCol->computeCellCenterOfMass());
9925 MCAuto<DataArrayInt> elts,eltsIndex;
9926 mesh2D->getCellsContainingPoints(baryRet1->begin(),baryRet1->getNumberOfTuples(),eps,elts,eltsIndex);
9927 MCAuto<DataArrayInt> eltsIndex2(eltsIndex->deltaShiftIndex());
9928 MCAuto<DataArrayInt> eltsIndex3(eltsIndex2->findIdsEqual(1));
9929 if(eltsIndex2->count(0)+eltsIndex3->getNumberOfTuples()!=ret1NonCol->getNumberOfCells())
9930 throw INTERP_KERNEL::Exception("Intersect2DMeshWith1DLine : internal error 1 !");
9931 MCAuto<DataArrayInt> cellsToBeModified(elts->buildUnique());
9932 MCAuto<DataArrayInt> untouchedCells(cellsToBeModified->buildComplement(mesh2D->getNumberOfCells()));
9933 if((DataArrayInt *)out0s)
9934 untouchedCells=untouchedCells->buildSubstraction(out0s);//if some edges in ret1 are colinear to descending mesh of mesh2D remove cells from untouched one
9935 std::vector< MCAuto<MEDCouplingUMesh> > outMesh2DSplit;
9936 // OK all is ready to insert in ret2 mesh
9937 if(!untouchedCells->empty())
9938 {// the most easy part, cells in mesh2D not impacted at all
9939 outMesh2DSplit.push_back(static_cast<MEDCouplingUMesh *>(mesh2D->buildPartOfMySelf(untouchedCells->begin(),untouchedCells->end())));
9940 outMesh2DSplit.back()->setCoords(ret1->getCoords());
9941 ret2->pushBackValsSilent(untouchedCells->begin(),untouchedCells->end());
9943 if((DataArrayInt *)out0s)
9944 {// here dealing with cells in out0s but not in cellsToBeModified
9945 MCAuto<DataArrayInt> fewModifiedCells(out0s->buildSubstraction(cellsToBeModified));
9946 const int *rdptr(dd3->begin()),*rdiptr(dd4->begin()),*dptr(dd1->begin()),*diptr(dd2->begin());
9947 for(const int *it=fewModifiedCells->begin();it!=fewModifiedCells->end();it++)
9949 outMesh2DSplit.push_back(BuildRefined2DCell(ret1->getCoords(),mesh2D,*it,dptr+diptr[*it],dptr+diptr[*it+1],intersectEdge1));
9950 ret1->setCoords(outMesh2DSplit.back()->getCoords());
9952 int offset(ret2->getNumberOfTuples());
9953 ret2->pushBackValsSilent(fewModifiedCells->begin(),fewModifiedCells->end());
9954 MCAuto<DataArrayInt> partOfRet3(DataArrayInt::New()); partOfRet3->alloc(2*idsInRet1Colinear->getNumberOfTuples(),1);
9955 partOfRet3->fillWithValue(std::numeric_limits<int>::max()); partOfRet3->rearrange(2);
9956 int kk(0),*ret3ptr(partOfRet3->getPointer());
9957 for(const int *it=idsInDescMesh2DForIdsInRetColinear->begin();it!=idsInDescMesh2DForIdsInRetColinear->end();it++,kk++)
9959 int faceId(std::abs(*it)-1);
9960 for(const int *it2=rdptr+rdiptr[faceId];it2!=rdptr+rdiptr[faceId+1];it2++)
9962 int tmp(fewModifiedCells->findIdFirstEqual(*it2));
9965 if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],-(*it))!=dptr+diptr[*it2+1])
9966 ret3ptr[2*kk]=tmp+offset;
9967 if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],(*it))!=dptr+diptr[*it2+1])
9968 ret3ptr[2*kk+1]=tmp+offset;
9971 {//the current edge is shared by a 2D cell that will be split just after
9972 if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],-(*it))!=dptr+diptr[*it2+1])
9973 ret3ptr[2*kk]=-(*it2+1);
9974 if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],(*it))!=dptr+diptr[*it2+1])
9975 ret3ptr[2*kk+1]=-(*it2+1);
9979 m1Desc->setCoords(ret1->getCoords());
9980 ret1NonCol->setCoords(ret1->getCoords());
9981 ret3->setPartOfValues3(partOfRet3,idsInRet1Colinear->begin(),idsInRet1Colinear->end(),0,2,1,true);
9982 if(!outMesh2DSplit.empty())
9984 DataArrayDouble *da(outMesh2DSplit.back()->getCoords());
9985 for(std::vector< MCAuto<MEDCouplingUMesh> >::iterator itt=outMesh2DSplit.begin();itt!=outMesh2DSplit.end();itt++)
9986 (*itt)->setCoords(da);
9989 cellsToBeModified=cellsToBeModified->buildUniqueNotSorted();
9990 for(const int *it=cellsToBeModified->begin();it!=cellsToBeModified->end();it++)
9992 MCAuto<DataArrayInt> idsNonColPerCell(elts->findIdsEqual(*it));
9993 idsNonColPerCell->transformWithIndArr(eltsIndex3->begin(),eltsIndex3->end());
9994 MCAuto<DataArrayInt> idsNonColPerCell2(idsInRet1NotColinear->selectByTupleId(idsNonColPerCell->begin(),idsNonColPerCell->end()));
9995 MCAuto<MEDCouplingUMesh> partOfMesh1CuttingCur2DCell(static_cast<MEDCouplingUMesh *>(ret1NonCol->buildPartOfMySelf(idsNonColPerCell->begin(),idsNonColPerCell->end())));
9996 MCAuto<DataArrayInt> partOfRet3;
9997 MCAuto<MEDCouplingUMesh> splitOfOneCell(BuildMesh2DCutFrom(eps,*it,m1Desc,partOfMesh1CuttingCur2DCell,dd1->begin()+dd2->getIJ(*it,0),dd1->begin()+dd2->getIJ((*it)+1,0),intersectEdge1,ret2->getNumberOfTuples(),partOfRet3));
9998 ret3->setPartOfValues3(partOfRet3,idsNonColPerCell2->begin(),idsNonColPerCell2->end(),0,2,1,true);
9999 outMesh2DSplit.push_back(splitOfOneCell);
10000 for(int i=0;i<splitOfOneCell->getNumberOfCells();i++)
10001 ret2->pushBackSilent(*it);
10004 std::size_t nbOfMeshes(outMesh2DSplit.size());
10005 std::vector<const MEDCouplingUMesh *> tmp(nbOfMeshes);
10006 for(std::size_t i=0;i<nbOfMeshes;i++)
10007 tmp[i]=outMesh2DSplit[i];
10009 ret1->getCoords()->setInfoOnComponents(compNames);
10010 MCAuto<MEDCouplingUMesh> ret2D(MEDCouplingUMesh::MergeUMeshesOnSameCoords(tmp));
10011 // To finish - filter ret3 - std::numeric_limits<int>::max() -> -1 - negate values must be resolved.
10012 ret3->rearrange(1);
10013 MCAuto<DataArrayInt> edgesToDealWith(ret3->findIdsStricltyNegative());
10014 for(const int *it=edgesToDealWith->begin();it!=edgesToDealWith->end();it++)
10016 int old2DCellId(-ret3->getIJ(*it,0)-1);
10017 MCAuto<DataArrayInt> candidates(ret2->findIdsEqual(old2DCellId));
10018 ret3->setIJ(*it,0,FindRightCandidateAmong(ret2D,candidates->begin(),candidates->end(),ret1,*it%2==0?-((*it)/2+1):(*it)/2+1,eps));// div by 2 because 2 components natively in ret3
10020 ret3->changeValue(std::numeric_limits<int>::max(),-1);
10021 ret3->rearrange(2);
10023 splitMesh1D=ret1.retn();
10024 splitMesh2D=ret2D.retn();
10025 cellIdInMesh2D=ret2.retn();
10026 cellIdInMesh1D=ret3.retn();
10030 * Private. Third step of the partitioning algorithm (Intersect2DMeshes): reconstruct full 2D cells from the
10031 * (newly created) nodes corresponding to the edge intersections.
10033 * @param[out] cr, crI connectivity of the resulting mesh
10034 * @param[out] cNb1, cNb2 correspondance arrays giving for the merged mesh the initial cells IDs in m1 / m2
10035 * TODO: describe input parameters
10037 void MEDCouplingUMesh::BuildIntersecting2DCellsFromEdges(double eps, const MEDCouplingUMesh *m1, const int *desc1, const int *descIndx1,
10038 const std::vector<std::vector<int> >& intesctEdges1, const std::vector< std::vector<int> >& colinear2,
10039 const MEDCouplingUMesh *m2, const int *desc2, const int *descIndx2, const std::vector<std::vector<int> >& intesctEdges2,
10040 const std::vector<double>& addCoords,
10041 std::vector<double>& addCoordsQuadratic, std::vector<int>& cr, std::vector<int>& crI, std::vector<int>& cNb1, std::vector<int>& cNb2)
10043 static const int SPACEDIM=2;
10044 const double *coo1(m1->getCoords()->getConstPointer());
10045 const int *conn1(m1->getNodalConnectivity()->getConstPointer()),*connI1(m1->getNodalConnectivityIndex()->getConstPointer());
10046 int offset1(m1->getNumberOfNodes());
10047 const double *coo2(m2->getCoords()->getConstPointer());
10048 const int *conn2(m2->getNodalConnectivity()->getConstPointer()),*connI2(m2->getNodalConnectivityIndex()->getConstPointer());
10049 int offset2(offset1+m2->getNumberOfNodes());
10050 int offset3(offset2+((int)addCoords.size())/2);
10051 MCAuto<DataArrayDouble> bbox1Arr(m1->getBoundingBoxForBBTree()),bbox2Arr(m2->getBoundingBoxForBBTree());
10052 const double *bbox1(bbox1Arr->begin()),*bbox2(bbox2Arr->begin());
10053 // Here a BBTree on 2D-cells, not on segments:
10054 BBTree<SPACEDIM,int> myTree(bbox2,0,0,m2->getNumberOfCells(),eps);
10055 int ncell1(m1->getNumberOfCells());
10057 for(int i=0;i<ncell1;i++)
10059 std::vector<int> candidates2;
10060 myTree.getIntersectingElems(bbox1+i*2*SPACEDIM,candidates2);
10061 std::map<INTERP_KERNEL::Node *,int> mapp;
10062 std::map<int,INTERP_KERNEL::Node *> mappRev;
10063 INTERP_KERNEL::QuadraticPolygon pol1;
10064 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn1[connI1[i]];
10065 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
10066 // Populate mapp and mappRev with nodes from the current cell (i) from mesh1 - this also builds the Node* objects:
10067 MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,/* output */mapp,mappRev);
10068 // pol1 is the full cell from mesh2, in QP format, with all the additional intersecting nodes.
10069 pol1.buildFromCrudeDataArray(mappRev,cm.isQuadratic(),conn1+connI1[i]+1,coo1,
10070 desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1);
10072 std::set<INTERP_KERNEL::Edge *> edges1;// store all edges of pol1 that are NOT consumed by intersect cells. If any after iteration over candidates2 -> a part of pol1 should appear in result
10073 std::set<INTERP_KERNEL::Edge *> edgesBoundary2;// store all edges that are on boundary of (pol2 intersect pol1) minus edges on pol1.
10074 INTERP_KERNEL::IteratorOnComposedEdge it1(&pol1);
10075 for(it1.first();!it1.finished();it1.next())
10076 edges1.insert(it1.current()->getPtr());
10078 std::map<int,std::vector<INTERP_KERNEL::ElementaryEdge *> > edgesIn2ForShare; // common edges
10079 std::vector<INTERP_KERNEL::QuadraticPolygon> pol2s(candidates2.size());
10081 for(std::vector<int>::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++,ii++)
10083 INTERP_KERNEL::NormalizedCellType typ2=(INTERP_KERNEL::NormalizedCellType)conn2[connI2[*it2]];
10084 const INTERP_KERNEL::CellModel& cm2=INTERP_KERNEL::CellModel::GetCellModel(typ2);
10085 // Complete mapping with elements coming from the current cell it2 in mesh2:
10086 MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,/* output */mapp,mappRev);
10087 // pol2 is the new QP in the final merged result.
10088 pol2s[ii].buildFromCrudeDataArray2(mappRev,cm2.isQuadratic(),conn2+connI2[*it2]+1,coo2,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,
10089 pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2, /* output */ edgesIn2ForShare);
10092 for(std::vector<int>::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++,ii++)
10094 INTERP_KERNEL::ComposedEdge::InitLocationsWithOther(pol1,pol2s[ii]);
10095 pol2s[ii].updateLocOfEdgeFromCrudeDataArray2(desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2);
10096 //MEDCouplingUMeshAssignOnLoc(pol1,pol2,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,colinear2);
10097 pol1.buildPartitionsAbs(pol2s[ii],edges1,edgesBoundary2,mapp,i,*it2,offset3,addCoordsQuadratic,cr,crI,cNb1,cNb2);
10099 // Deals with remaining (non-consumed) edges from m1: these are the edges that were never touched
10100 // by m2 but that we still want to keep in the final result.
10101 if(!edges1.empty())
10105 INTERP_KERNEL::QuadraticPolygon::ComputeResidual(pol1,edges1,edgesBoundary2,mapp,offset3,i,addCoordsQuadratic,cr,crI,cNb1,cNb2);
10107 catch(INTERP_KERNEL::Exception& e)
10109 std::ostringstream oss; oss << "Error when computing residual of cell #" << i << " in source/m1 mesh ! Maybe the neighbours of this cell in mesh are not well connected !\n" << "The deep reason is the following : " << e.what();
10110 throw INTERP_KERNEL::Exception(oss.str().c_str());
10113 for(std::map<int,INTERP_KERNEL::Node *>::const_iterator it=mappRev.begin();it!=mappRev.end();it++)
10114 (*it).second->decrRef();
10119 * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
10120 * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
10121 * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
10122 * The caller is to deal with the resulting DataArrayInt.
10123 * \throw If the coordinate array is not set.
10124 * \throw If the nodal connectivity of the cells is not defined.
10125 * \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
10126 * \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
10128 * \sa DataArrayInt::sortEachPairToMakeALinkedList
10130 DataArrayInt *MEDCouplingUMesh::orderConsecutiveCells1D() const
10132 checkFullyDefined();
10133 if(getMeshDimension()!=1)
10134 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
10136 // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
10137 MCAuto<DataArrayInt> _d(DataArrayInt::New()),_dI(DataArrayInt::New());
10138 MCAuto<DataArrayInt> _rD(DataArrayInt::New()),_rDI(DataArrayInt::New());
10139 MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
10140 const int *d(_d->getConstPointer()), *dI(_dI->getConstPointer());
10141 const int *rD(_rD->getConstPointer()), *rDI(_rDI->getConstPointer());
10142 MCAuto<DataArrayInt> _dsi(_rDI->deltaShiftIndex());
10143 const int * dsi(_dsi->getConstPointer());
10144 MCAuto<DataArrayInt> dsii = _dsi->findIdsNotInRange(0,3);
10146 if (dsii->getNumberOfTuples())
10147 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
10149 int nc(getNumberOfCells());
10150 MCAuto<DataArrayInt> result(DataArrayInt::New());
10151 result->alloc(nc,1);
10153 // set of edges not used so far
10154 std::set<int> edgeSet;
10155 for (int i=0; i<nc; edgeSet.insert(i), i++);
10159 // while we have points with only one neighbor segments
10162 std::list<int> linePiece;
10163 // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
10164 for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
10166 // Fill the list forward (resp. backward) from the start segment:
10167 int activeSeg = startSeg;
10168 int prevPointId = -20;
10170 while (!edgeSet.empty())
10172 if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
10175 linePiece.push_back(activeSeg);
10177 linePiece.push_front(activeSeg);
10178 edgeSet.erase(activeSeg);
10181 int ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
10182 ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
10183 if (dsi[ptId] == 1) // hitting the end of the line
10185 prevPointId = ptId;
10186 int seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
10187 activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
10190 // Done, save final piece into DA:
10191 std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
10192 newIdx += linePiece.size();
10194 // identify next valid start segment (one which is not consumed)
10195 if(!edgeSet.empty())
10196 startSeg = *(edgeSet.begin());
10198 while (!edgeSet.empty());
10199 return result.retn();
10204 void IKGeo2DInternalMapper2(INTERP_KERNEL::Node *n, const std::map<MCAuto<INTERP_KERNEL::Node>,int>& m, int forbVal0, int forbVal1, std::vector<int>& isect)
10206 MCAuto<INTERP_KERNEL::Node> nTmp(n); nTmp->incrRef();
10207 std::map<MCAuto<INTERP_KERNEL::Node>,int>::const_iterator it(m.find(nTmp));
10209 throw INTERP_KERNEL::Exception("Internal error in remapping !");
10210 int v((*it).second);
10211 if(v==forbVal0 || v==forbVal1)
10213 if(std::find(isect.begin(),isect.end(),v)==isect.end())
10214 isect.push_back(v);
10217 bool IKGeo2DInternalMapper(const INTERP_KERNEL::ComposedEdge& c, const std::map<MCAuto<INTERP_KERNEL::Node>,int>& m, int forbVal0, int forbVal1, std::vector<int>& isect)
10222 bool presenceOfOn(false);
10223 for(int i=0;i<sz;i++)
10225 INTERP_KERNEL::ElementaryEdge *e(c[i]);
10226 if(e->getLoc()!=INTERP_KERNEL::FULL_ON_1)
10228 IKGeo2DInternalMapper2(e->getStartNode(),m,forbVal0,forbVal1,isect);
10229 IKGeo2DInternalMapper2(e->getEndNode(),m,forbVal0,forbVal1,isect);
10231 return presenceOfOn;
10237 * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
10238 * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
10239 * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
10240 * a minimal creation of new nodes is wanted.
10241 * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
10242 * nodes if a SEG3 is split without information of middle.
10243 * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
10244 * avoid to have a non conform mesh.
10246 * \return int - the number of new nodes created (in most of cases 0).
10248 * \throw If \a this is not coherent.
10249 * \throw If \a this has not spaceDim equal to 2.
10250 * \throw If \a this has not meshDim equal to 2.
10251 * \throw If some subcells needed to be split are orphan.
10252 * \sa MEDCouplingUMesh::conformize2D
10254 int MEDCouplingUMesh::split2DCells(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *midOpt, const DataArrayInt *midOptI)
10256 if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
10257 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
10258 desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
10259 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10260 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10261 if(midOpt==0 && midOptI==0)
10263 split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
10266 else if(midOpt!=0 && midOptI!=0)
10267 return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
10269 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
10273 * \b WARNING this method is \b potentially \b non \b const (if returned array is empty).
10274 * \b WARNING this method lead to have a non geometric type sorted mesh (for MED file users) !
10275 * This method performs a conformization of \b this. So if a edge in \a this can be split into entire edges in \a this this method
10276 * will suppress such edges to use sub edges in \a this. So this method does not add nodes in \a this if merged edges are both linear (INTERP_KERNEL::NORM_SEG2).
10277 * In the other cases new nodes can be created. If any are created, they will be appended at the end of the coordinates object before the invokation of this method.
10279 * Whatever the returned value, this method does not alter the order of cells in \a this neither the orientation of cells.
10280 * The modified cells, if any, are systematically declared as NORM_POLYGON or NORM_QPOLYG depending on the initial quadraticness of geometric type.
10282 * This method expects that \b this has a meshDim equal 2 and spaceDim equal to 2 too.
10283 * This method expects that all nodes in \a this are not closer than \a eps.
10284 * If it is not the case you can invoke MEDCouplingUMesh::mergeNodes before calling this method.
10286 * \param [in] eps the relative error to detect merged edges.
10287 * \return DataArrayInt * - The list of cellIds in \a this that have been subdivided. If empty, nothing changed in \a this (as if it were a const method). The array is a newly allocated array
10288 * that the user is expected to deal with.
10290 * \throw If \a this is not coherent.
10291 * \throw If \a this has not spaceDim equal to 2.
10292 * \throw If \a this has not meshDim equal to 2.
10293 * \sa MEDCouplingUMesh::mergeNodes, MEDCouplingUMesh::split2DCells
10295 DataArrayInt *MEDCouplingUMesh::conformize2D(double eps)
10297 static const int SPACEDIM=2;
10298 checkConsistencyLight();
10299 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10300 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::conformize2D : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10301 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
10302 MCAuto<MEDCouplingUMesh> mDesc(buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));
10303 const int *c(mDesc->getNodalConnectivity()->getConstPointer()),*ci(mDesc->getNodalConnectivityIndex()->getConstPointer()),*rd(revDesc1->getConstPointer()),*rdi(revDescIndx1->getConstPointer());
10304 MCAuto<DataArrayDouble> bboxArr(mDesc->getBoundingBoxForBBTree());
10305 const double *bbox(bboxArr->begin()),*coords(getCoords()->begin());
10306 int nCell(getNumberOfCells()),nDescCell(mDesc->getNumberOfCells());
10307 std::vector< std::vector<int> > intersectEdge(nDescCell),overlapEdge(nDescCell);
10308 std::vector<double> addCoo;
10309 BBTree<SPACEDIM,int> myTree(bbox,0,0,nDescCell,-eps);
10310 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10311 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10312 for(int i=0;i<nDescCell;i++)
10314 std::vector<int> candidates;
10315 myTree.getIntersectingElems(bbox+i*2*SPACEDIM,candidates);
10316 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
10319 std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
10320 INTERP_KERNEL::Edge *e1(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coords,m)),
10321 *e2(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[*it]],c+ci[*it]+1,coords,m));
10322 INTERP_KERNEL::MergePoints merge;
10323 INTERP_KERNEL::QuadraticPolygon c1,c2;
10324 e1->intersectWith(e2,merge,c1,c2);
10325 e1->decrRef(); e2->decrRef();
10326 if(IKGeo2DInternalMapper(c1,m,c[ci[i]+1],c[ci[i]+2],intersectEdge[i]))
10327 overlapEdge[i].push_back(*it);
10328 if(IKGeo2DInternalMapper(c2,m,c[ci[*it]+1],c[ci[*it]+2],intersectEdge[*it]))
10329 overlapEdge[*it].push_back(i);
10332 // splitting done. sort intersect point in intersectEdge.
10333 std::vector< std::vector<int> > middle(nDescCell);
10334 int nbOf2DCellsToBeSplit(0);
10335 bool middleNeedsToBeUsed(false);
10336 std::vector<bool> cells2DToTreat(nDescCell,false);
10337 for(int i=0;i<nDescCell;i++)
10339 std::vector<int>& isect(intersectEdge[i]);
10340 int sz((int)isect.size());
10343 std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
10344 INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coords,m));
10345 e->sortSubNodesAbs(coords,isect);
10350 int idx0(rdi[i]),idx1(rdi[i+1]);
10352 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::conformize2D : internal error #0 !");
10353 if(!cells2DToTreat[rd[idx0]])
10355 cells2DToTreat[rd[idx0]]=true;
10356 nbOf2DCellsToBeSplit++;
10358 // try to reuse at most eventual 'middle' of SEG3
10359 std::vector<int>& mid(middle[i]);
10360 mid.resize(sz+1,-1);
10361 if((INTERP_KERNEL::NormalizedCellType)c[ci[i]]==INTERP_KERNEL::NORM_SEG3)
10363 middleNeedsToBeUsed=true;
10364 const std::vector<int>& candidates(overlapEdge[i]);
10365 std::vector<int> trueCandidates;
10366 for(std::vector<int>::const_iterator itc=candidates.begin();itc!=candidates.end();itc++)
10367 if((INTERP_KERNEL::NormalizedCellType)c[ci[*itc]]==INTERP_KERNEL::NORM_SEG3)
10368 trueCandidates.push_back(*itc);
10369 int stNode(c[ci[i]+1]),endNode(isect[0]);
10370 for(int j=0;j<sz+1;j++)
10372 for(std::vector<int>::const_iterator itc=trueCandidates.begin();itc!=trueCandidates.end();itc++)
10374 int tmpSt(c[ci[*itc]+1]),tmpEnd(c[ci[*itc]+2]);
10375 if((tmpSt==stNode && tmpEnd==endNode) || (tmpSt==endNode && tmpEnd==stNode))
10376 { mid[j]=*itc; break; }
10379 endNode=j<sz-1?isect[j+1]:c[ci[i]+2];
10384 MCAuto<DataArrayInt> ret(DataArrayInt::New()),notRet(DataArrayInt::New()); ret->alloc(nbOf2DCellsToBeSplit,1);
10385 if(nbOf2DCellsToBeSplit==0)
10388 int *retPtr(ret->getPointer());
10389 for(int i=0;i<nCell;i++)
10390 if(cells2DToTreat[i])
10393 MCAuto<DataArrayInt> mSafe,nSafe,oSafe,pSafe,qSafe,rSafe;
10394 DataArrayInt *m(0),*n(0),*o(0),*p(0),*q(0),*r(0);
10395 MEDCouplingUMesh::ExtractFromIndexedArrays(ret->begin(),ret->end(),desc1,descIndx1,m,n); mSafe=m; nSafe=n;
10396 DataArrayInt::PutIntoToSkylineFrmt(intersectEdge,o,p); oSafe=o; pSafe=p;
10397 if(middleNeedsToBeUsed)
10398 { DataArrayInt::PutIntoToSkylineFrmt(middle,q,r); qSafe=q; rSafe=r; }
10399 MCAuto<MEDCouplingUMesh> modif(static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(ret->begin(),ret->end(),true)));
10400 int nbOfNodesCreated(modif->split2DCells(mSafe,nSafe,oSafe,pSafe,qSafe,rSafe));
10401 setCoords(modif->getCoords());//if nbOfNodesCreated==0 modif and this have the same coordinates pointer so this line has no effect. But for quadratic cases this line is important.
10402 setPartOfMySelf(ret->begin(),ret->end(),*modif);
10404 bool areNodesMerged; int newNbOfNodes;
10405 if(nbOfNodesCreated!=0)
10406 MCAuto<DataArrayInt> tmp(mergeNodes(eps,areNodesMerged,newNbOfNodes));
10412 * This non const method works on 2D mesh. This method scans every cell in \a this and look if each edge constituting this cell is not mergeable with neighbors edges of that cell.
10413 * If yes, the cell is "repaired" to minimize at most its number of edges. So this method do not change the overall shape of cells in \a this (with eps precision).
10414 * This method do not take care of shared edges between cells, so this method can lead to a non conform mesh (\a this). If a conform mesh is required you're expected
10415 * to invoke MEDCouplingUMesh::mergeNodes and MEDCouplingUMesh::conformize2D right after this call.
10416 * This method works on any 2D geometric types of cell (even static one). If a cell is touched its type becomes dynamic automaticaly. For 2D "repaired" quadratic cells
10417 * new nodes for center of merged edges is are systematically created and appended at the end of the previously existing nodes.
10419 * If the returned array is empty it means that nothing has changed in \a this (as if it were a const method). If the array is not empty the connectivity of \a this is modified
10420 * using new instance, idem for coordinates.
10422 * If \a this is constituted by only linear 2D cells, this method is close to the computation of the convex hull of each cells in \a this.
10424 * \return DataArrayInt * - The list of cellIds in \a this that have at least one edge colinearized.
10426 * \throw If \a this is not coherent.
10427 * \throw If \a this has not spaceDim equal to 2.
10428 * \throw If \a this has not meshDim equal to 2.
10430 * \sa MEDCouplingUMesh::conformize2D, MEDCouplingUMesh::mergeNodes, MEDCouplingUMesh::convexEnvelop2D.
10432 DataArrayInt *MEDCouplingUMesh::colinearize2D(double eps)
10434 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
10435 checkConsistencyLight();
10436 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10437 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::colinearize2D : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10438 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10439 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10440 int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
10441 const int *cptr(_nodal_connec->begin()),*ciptr(_nodal_connec_index->begin());
10442 MCAuto<DataArrayInt> newc(DataArrayInt::New()),newci(DataArrayInt::New()); newci->alloc(nbOfCells+1,1); newc->alloc(0,1); newci->setIJ(0,0,0);
10443 MCAuto<DataArrayDouble> appendedCoords(DataArrayDouble::New()); appendedCoords->alloc(0,1);//1 not 2 it is not a bug.
10444 const double *coords(_coords->begin());
10445 int *newciptr(newci->getPointer());
10446 for(int i=0;i<nbOfCells;i++,newciptr++,ciptr++)
10448 if(Colinearize2DCell(coords,cptr+ciptr[0],cptr+ciptr[1],nbOfNodes,newc,appendedCoords))
10449 ret->pushBackSilent(i);
10450 newciptr[1]=newc->getNumberOfTuples();
10455 if(!appendedCoords->empty())
10457 appendedCoords->rearrange(2);
10458 MCAuto<DataArrayDouble> newCoords(DataArrayDouble::Aggregate(getCoords(),appendedCoords));//treat info on components
10460 setCoords(newCoords);
10463 setConnectivity(newc,newci,true);
10468 * \param [out] intersectEdge1 - for each cell in \a m1Desc returns the result of the split. The result is given using pair of int given resp start and stop.
10469 * So for all edge \a i in \a m1Desc \a intersectEdge1[i] is of length 2*n where n is the number of sub edges.
10470 * And for each j in [1,n) intersect[i][2*(j-1)+1]==intersect[i][2*j].
10471 * \param [out] subDiv2 - for each cell in \a m2Desc returns nodes that split it using convention \a m1Desc first, then \a m2Desc, then addCoo
10472 * \param [out] colinear2 - for each cell in \a m2Desc returns the edges in \a m1Desc that are colinear to it.
10473 * \param [out] addCoo - nodes to be append at the end
10474 * \param [out] mergedNodes - gives all pair of nodes of \a m2Desc that have same location than some nodes in \a m1Desc. key is id in \a m2Desc offseted and value is id in \a m1Desc.
10476 void MEDCouplingUMesh::Intersect1DMeshes(const MEDCouplingUMesh *m1Desc, const MEDCouplingUMesh *m2Desc, double eps,
10477 std::vector< std::vector<int> >& intersectEdge1, std::vector< std::vector<int> >& colinear2, std::vector< std::vector<int> >& subDiv2, std::vector<double>& addCoo, std::map<int,int>& mergedNodes)
10479 static const int SPACEDIM=2;
10480 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10481 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10482 const int *c1(m1Desc->getNodalConnectivity()->getConstPointer()),*ci1(m1Desc->getNodalConnectivityIndex()->getConstPointer());
10483 // Build BB tree of all edges in the tool mesh (second mesh)
10484 MCAuto<DataArrayDouble> bbox1Arr(m1Desc->getBoundingBoxForBBTree()),bbox2Arr(m2Desc->getBoundingBoxForBBTree());
10485 const double *bbox1(bbox1Arr->begin()),*bbox2(bbox2Arr->begin());
10486 int nDescCell1(m1Desc->getNumberOfCells()),nDescCell2(m2Desc->getNumberOfCells());
10487 intersectEdge1.resize(nDescCell1);
10488 colinear2.resize(nDescCell2);
10489 subDiv2.resize(nDescCell2);
10490 BBTree<SPACEDIM,int> myTree(bbox2,0,0,m2Desc->getNumberOfCells(),-eps);
10492 std::vector<int> candidates1(1);
10493 int offset1(m1Desc->getNumberOfNodes());
10494 int offset2(offset1+m2Desc->getNumberOfNodes());
10495 for(int i=0;i<nDescCell1;i++) // for all edges in the first mesh
10497 std::vector<int> candidates2; // edges of mesh2 candidate for intersection
10498 myTree.getIntersectingElems(bbox1+i*2*SPACEDIM,candidates2);
10499 if(!candidates2.empty()) // candidates2 holds edges from the second mesh potentially intersecting current edge i in mesh1
10501 std::map<INTERP_KERNEL::Node *,int> map1,map2;
10502 // pol2 is not necessarily a closed polygon: just a set of (quadratic) edges (same as candidates2) in the Geometric DS format
10503 INTERP_KERNEL::QuadraticPolygon *pol2=MEDCouplingUMeshBuildQPFromMesh(m2Desc,candidates2,map2);
10505 INTERP_KERNEL::QuadraticPolygon *pol1=MEDCouplingUMeshBuildQPFromMesh(m1Desc,candidates1,map1);
10506 // This following part is to avoid that some removed nodes (for example due to a merge between pol1 and pol2) are replaced by a newly created one
10507 // This trick guarantees that Node * are discriminant (i.e. form a unique identifier)
10508 std::set<INTERP_KERNEL::Node *> nodes;
10509 pol1->getAllNodes(nodes); pol2->getAllNodes(nodes);
10510 std::size_t szz(nodes.size());
10511 std::vector< MCAuto<INTERP_KERNEL::Node> > nodesSafe(szz);
10512 std::set<INTERP_KERNEL::Node *>::const_iterator itt(nodes.begin());
10513 for(std::size_t iii=0;iii<szz;iii++,itt++)
10514 { (*itt)->incrRef(); nodesSafe[iii]=*itt; }
10515 // end of protection
10516 // Performs egde cutting:
10517 pol1->splitAbs(*pol2,map1,map2,offset1,offset2,candidates2,intersectEdge1[i],i,colinear2,subDiv2,addCoo,mergedNodes);
10522 // Copy the edge (take only the two first points, ie discard quadratic point at this stage)
10523 intersectEdge1[i].insert(intersectEdge1[i].end(),c1+ci1[i]+1,c1+ci1[i]+3);
10528 * This method is private and is the first step of Partition of 2D mesh (spaceDim==2 and meshDim==2).
10529 * It builds the descending connectivity of the two meshes, and then using a binary tree
10530 * it computes the edge intersections. This results in new points being created : they're stored in addCoo.
10531 * Documentation about parameters colinear2 and subDiv2 can be found in method QuadraticPolygon::splitAbs().
10533 void MEDCouplingUMesh::IntersectDescending2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2, double eps,
10534 std::vector< std::vector<int> >& intersectEdge1, std::vector< std::vector<int> >& colinear2, std::vector< std::vector<int> >& subDiv2,
10535 MEDCouplingUMesh *& m1Desc, DataArrayInt *&desc1, DataArrayInt *&descIndx1, DataArrayInt *&revDesc1, DataArrayInt *&revDescIndx1,
10536 std::vector<double>& addCoo,
10537 MEDCouplingUMesh *& m2Desc, DataArrayInt *&desc2, DataArrayInt *&descIndx2, DataArrayInt *&revDesc2, DataArrayInt *&revDescIndx2)
10539 // Build desc connectivity
10540 desc1=DataArrayInt::New(); descIndx1=DataArrayInt::New(); revDesc1=DataArrayInt::New(); revDescIndx1=DataArrayInt::New();
10541 desc2=DataArrayInt::New();
10542 descIndx2=DataArrayInt::New();
10543 revDesc2=DataArrayInt::New();
10544 revDescIndx2=DataArrayInt::New();
10545 MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(revDesc1),dd4(revDescIndx1);
10546 MCAuto<DataArrayInt> dd5(desc2),dd6(descIndx2),dd7(revDesc2),dd8(revDescIndx2);
10547 m1Desc=m1->buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1);
10548 m2Desc=m2->buildDescendingConnectivity2(desc2,descIndx2,revDesc2,revDescIndx2);
10549 MCAuto<MEDCouplingUMesh> dd9(m1Desc),dd10(m2Desc);
10550 std::map<int,int> notUsedMap;
10551 Intersect1DMeshes(m1Desc,m2Desc,eps,intersectEdge1,colinear2,subDiv2,addCoo,notUsedMap);
10552 m1Desc->incrRef(); desc1->incrRef(); descIndx1->incrRef(); revDesc1->incrRef(); revDescIndx1->incrRef();
10553 m2Desc->incrRef(); desc2->incrRef(); descIndx2->incrRef(); revDesc2->incrRef(); revDescIndx2->incrRef();
10557 * This method performs the 2nd step of Partition of 2D mesh.
10558 * This method has 4 inputs :
10559 * - a mesh 'm1' with meshDim==1 and a SpaceDim==2
10560 * - a mesh 'm2' with meshDim==1 and a SpaceDim==2
10561 * - subDiv of size 'm2->getNumberOfCells()' that lists for each seg cell in 'm' the splitting node ids randomly sorted.
10562 * The aim of this method is to sort the splitting nodes, if any, and to put them in 'intersectEdge' output parameter based on edges of mesh 'm2'
10563 * Nodes end up lying consecutively on a cutted edge.
10564 * \param m1 is expected to be a mesh of meshDimension equal to 1 and spaceDim equal to 2. No check of that is performed by this method.
10565 * (Only present for its coords in case of 'subDiv' shares some nodes of 'm1')
10566 * \param m2 is expected to be a mesh of meshDimension equal to 1 and spaceDim equal to 2. No check of that is performed by this method.
10567 * \param addCoo input parameter with additional nodes linked to intersection of the 2 meshes.
10568 * \param[out] intersectEdge the same content as subDiv, but correclty oriented.
10570 void MEDCouplingUMesh::BuildIntersectEdges(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2,
10571 const std::vector<double>& addCoo,
10572 const std::vector< std::vector<int> >& subDiv, std::vector< std::vector<int> >& intersectEdge)
10574 int offset1=m1->getNumberOfNodes();
10575 int ncell=m2->getNumberOfCells();
10576 const int *c=m2->getNodalConnectivity()->getConstPointer();
10577 const int *cI=m2->getNodalConnectivityIndex()->getConstPointer();
10578 const double *coo=m2->getCoords()->getConstPointer();
10579 const double *cooBis=m1->getCoords()->getConstPointer();
10580 int offset2=offset1+m2->getNumberOfNodes();
10581 intersectEdge.resize(ncell);
10582 for(int i=0;i<ncell;i++,cI++)
10584 const std::vector<int>& divs=subDiv[i];
10585 int nnode=cI[1]-cI[0]-1;
10586 std::map<int, std::pair<INTERP_KERNEL::Node *,bool> > mapp2;
10587 std::map<INTERP_KERNEL::Node *, int> mapp22;
10588 for(int j=0;j<nnode;j++)
10590 INTERP_KERNEL::Node *nn=new INTERP_KERNEL::Node(coo[2*c[(*cI)+j+1]],coo[2*c[(*cI)+j+1]+1]);
10591 int nnid=c[(*cI)+j+1];
10592 mapp2[nnid]=std::pair<INTERP_KERNEL::Node *,bool>(nn,true);
10593 mapp22[nn]=nnid+offset1;
10595 INTERP_KERNEL::Edge *e=MEDCouplingUMeshBuildQPFromEdge((INTERP_KERNEL::NormalizedCellType)c[*cI],mapp2,c+(*cI)+1);
10596 for(std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >::const_iterator it=mapp2.begin();it!=mapp2.end();it++)
10597 ((*it).second.first)->decrRef();
10598 std::vector<INTERP_KERNEL::Node *> addNodes(divs.size());
10599 std::map<INTERP_KERNEL::Node *,int> mapp3;
10600 for(std::size_t j=0;j<divs.size();j++)
10603 INTERP_KERNEL::Node *tmp=0;
10605 tmp=new INTERP_KERNEL::Node(cooBis[2*id],cooBis[2*id+1]);
10606 else if(id<offset2)
10607 tmp=new INTERP_KERNEL::Node(coo[2*(id-offset1)],coo[2*(id-offset1)+1]);//if it happens, bad news mesh 'm2' is non conform.
10609 tmp=new INTERP_KERNEL::Node(addCoo[2*(id-offset2)],addCoo[2*(id-offset2)+1]);
10613 e->sortIdsAbs(addNodes,mapp22,mapp3,intersectEdge[i]);
10614 for(std::vector<INTERP_KERNEL::Node *>::const_iterator it=addNodes.begin();it!=addNodes.end();it++)
10621 * This method is part of the Slice3D algorithm. It is the first step of assembly process, ones coordinates have been computed (by MEDCouplingUMesh::split3DCurveWithPlane method).
10622 * This method allows to compute given the status of 3D curve cells and the descending connectivity 3DSurf->3DCurve to deduce the intersection of each 3D surf cells
10623 * with a plane. The result will be put in 'cut3DSuf' out parameter.
10624 * \param [in] cut3DCurve input paramter that gives for each 3DCurve cell if it owns fully to the plane or partially.
10625 * \param [out] nodesOnPlane, returns all the nodes that are on the plane.
10626 * \param [in] nodal3DSurf is the nodal connectivity of 3D surf mesh.
10627 * \param [in] nodalIndx3DSurf is the nodal connectivity index of 3D surf mesh.
10628 * \param [in] nodal3DCurve is the nodal connectivity of 3D curve mesh.
10629 * \param [in] nodal3DIndxCurve is the nodal connectivity index of 3D curve mesh.
10630 * \param [in] desc is the descending connectivity 3DSurf->3DCurve
10631 * \param [in] descIndx is the descending connectivity index 3DSurf->3DCurve
10632 * \param [out] cut3DSuf input/output param.
10634 void MEDCouplingUMesh::AssemblyForSplitFrom3DCurve(const std::vector<int>& cut3DCurve, std::vector<int>& nodesOnPlane, const int *nodal3DSurf, const int *nodalIndx3DSurf,
10635 const int *nodal3DCurve, const int *nodalIndx3DCurve,
10636 const int *desc, const int *descIndx,
10637 std::vector< std::pair<int,int> >& cut3DSurf)
10639 std::set<int> nodesOnP(nodesOnPlane.begin(),nodesOnPlane.end());
10640 int nbOf3DSurfCell=(int)cut3DSurf.size();
10641 for(int i=0;i<nbOf3DSurfCell;i++)
10643 std::vector<int> res;
10644 int offset=descIndx[i];
10645 int nbOfSeg=descIndx[i+1]-offset;
10646 for(int j=0;j<nbOfSeg;j++)
10648 int edgeId=desc[offset+j];
10649 int status=cut3DCurve[edgeId];
10653 res.push_back(status);
10656 res.push_back(nodal3DCurve[nodalIndx3DCurve[edgeId]+1]);
10657 res.push_back(nodal3DCurve[nodalIndx3DCurve[edgeId]+2]);
10665 cut3DSurf[i].first=res[0]; cut3DSurf[i].second=res[1];
10671 std::set<int> s1(nodal3DSurf+nodalIndx3DSurf[i]+1,nodal3DSurf+nodalIndx3DSurf[i+1]);
10672 std::set_intersection(nodesOnP.begin(),nodesOnP.end(),s1.begin(),s1.end(),std::back_insert_iterator< std::vector<int> >(res));
10675 cut3DSurf[i].first=res[0]; cut3DSurf[i].second=res[1];
10679 cut3DSurf[i].first=-1; cut3DSurf[i].second=-1;
10684 {// case when plane is on a multi colinear edge of a polyhedron
10685 if((int)res.size()==2*nbOfSeg)
10687 cut3DSurf[i].first=-2; cut3DSurf[i].second=i;
10690 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AssemblyPointsFrom3DCurve : unexpected situation !");
10697 * \a this is expected to be a mesh with spaceDim==3 and meshDim==3. If not an exception will be thrown.
10698 * This method is part of the Slice3D algorithm. It is the second step of assembly process, ones coordinates have been computed (by MEDCouplingUMesh::split3DCurveWithPlane method).
10699 * This method allows to compute given the result of 3D surf cells with plane and the descending connectivity 3D->3DSurf to deduce the intersection of each 3D cells
10700 * with a plane. The result will be put in 'nodalRes' 'nodalResIndx' and 'cellIds' out parameters.
10701 * \param cut3DSurf input paramter that gives for each 3DSurf its intersection with plane (result of MEDCouplingUMesh::AssemblyForSplitFrom3DCurve).
10702 * \param desc is the descending connectivity 3D->3DSurf
10703 * \param descIndx is the descending connectivity index 3D->3DSurf
10705 void MEDCouplingUMesh::assemblyForSplitFrom3DSurf(const std::vector< std::pair<int,int> >& cut3DSurf,
10706 const int *desc, const int *descIndx,
10707 DataArrayInt *nodalRes, DataArrayInt *nodalResIndx, DataArrayInt *cellIds) const
10709 checkFullyDefined();
10710 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
10711 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::assemblyForSplitFrom3DSurf works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
10712 const int *nodal3D=_nodal_connec->getConstPointer();
10713 const int *nodalIndx3D=_nodal_connec_index->getConstPointer();
10714 int nbOfCells=getNumberOfCells();
10715 for(int i=0;i<nbOfCells;i++)
10717 std::map<int, std::set<int> > m;
10718 int offset=descIndx[i];
10719 int nbOfFaces=descIndx[i+1]-offset;
10722 for(int j=0;j<nbOfFaces;j++)
10724 const std::pair<int,int>& p=cut3DSurf[desc[offset+j]];
10725 if(p.first!=-1 && p.second!=-1)
10729 start=p.first; end=p.second;
10730 m[p.first].insert(p.second);
10731 m[p.second].insert(p.first);
10735 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodal3D[nodalIndx3D[i]]);
10736 int sz=nodalIndx3D[i+1]-nodalIndx3D[i]-1;
10737 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
10738 INTERP_KERNEL::NormalizedCellType cmsId;
10739 unsigned nbOfNodesSon=cm.fillSonCellNodalConnectivity2(j,nodal3D+nodalIndx3D[i]+1,sz,tmp,cmsId);
10740 start=tmp[0]; end=tmp[nbOfNodesSon-1];
10741 for(unsigned k=0;k<nbOfNodesSon;k++)
10743 m[tmp[k]].insert(tmp[(k+1)%nbOfNodesSon]);
10744 m[tmp[(k+1)%nbOfNodesSon]].insert(tmp[k]);
10751 std::vector<int> conn(1,(int)INTERP_KERNEL::NORM_POLYGON);
10755 std::map<int, std::set<int> >::const_iterator it=m.find(start);
10756 const std::set<int>& s=(*it).second;
10757 std::set<int> s2; s2.insert(prev);
10759 std::set_difference(s.begin(),s.end(),s2.begin(),s2.end(),inserter(s3,s3.begin()));
10762 int val=*s3.begin();
10763 conn.push_back(start);
10770 conn.push_back(end);
10773 nodalRes->insertAtTheEnd(conn.begin(),conn.end());
10774 nodalResIndx->pushBackSilent(nodalRes->getNumberOfTuples());
10775 cellIds->pushBackSilent(i);
10781 * This method compute the convex hull of a single 2D cell. This method tries to conserve at maximum the given input connectivity. In particular, if the orientation of cell is not clockwise
10782 * as in MED format norm. If definitely the result of Jarvis algorithm is not matchable with the input connectivity, the result will be copied into \b nodalConnecOut parameter and
10783 * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
10784 * This method excepts that \b coords parameter is expected to be in dimension 2. [ \b nodalConnBg , \b nodalConnEnd ) is the nodal connectivity of the input
10785 * cell (geometric cell type included at the position 0). If the meshdimension of the input cell is not equal to 2 an INTERP_KERNEL::Exception will be thrown.
10787 * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
10789 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const int *nodalConnBg, const int *nodalConnEnd, DataArrayInt *nodalConnecOut)
10791 std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
10794 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
10795 if(cm.getDimension()==2)
10797 const int *node=nodalConnBg+1;
10798 int startNode=*node++;
10799 double refX=coords[2*startNode];
10800 for(;node!=nodalConnEnd;node++)
10802 if(coords[2*(*node)]<refX)
10805 refX=coords[2*startNode];
10808 std::vector<int> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
10812 double angle0=-M_PI/2;
10817 double angleNext=0.;
10818 while(nextNode!=startNode)
10822 for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
10824 if(*node!=tmpOut.back() && *node!=prevNode)
10826 tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
10827 double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
10832 res=angle0-angleM+2.*M_PI;
10841 if(nextNode!=startNode)
10843 angle0=angleNext-M_PI;
10846 prevNode=tmpOut.back();
10847 tmpOut.push_back(nextNode);
10850 std::vector<int> tmp3(2*(sz-1));
10851 std::vector<int>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
10852 std::copy(nodalConnBg+1,nodalConnEnd,it);
10853 if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
10855 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
10858 if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
10860 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
10865 nodalConnecOut->pushBackSilent((int)INTERP_KERNEL::NORM_POLYGON);
10866 nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
10871 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
10874 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
10878 * This method works on an input pair (\b arr, \b arrIndx) where \b arr indexes is in \b arrIndx.
10879 * This method will not impact the size of inout parameter \b arrIndx but the size of \b arr will be modified in case of suppression.
10881 * \param [in] idsToRemoveBg begin of set of ids to remove in \b arr (included)
10882 * \param [in] idsToRemoveEnd end of set of ids to remove in \b arr (excluded)
10883 * \param [in,out] arr array in which the remove operation will be done.
10884 * \param [in,out] arrIndx array in the remove operation will modify
10885 * \param [in] offsetForRemoval (by default 0) offset so that for each i in [0,arrIndx->getNumberOfTuples()-1) removal process will be performed in the following range [arr+arrIndx[i]+offsetForRemoval,arr+arr[i+1])
10886 * \return true if \b arr and \b arrIndx have been modified, false if not.
10888 bool MEDCouplingUMesh::RemoveIdsFromIndexedArrays(const int *idsToRemoveBg, const int *idsToRemoveEnd, DataArrayInt *arr, DataArrayInt *arrIndx, int offsetForRemoval)
10890 if(!arrIndx || !arr)
10891 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : some input arrays are empty !");
10892 if(offsetForRemoval<0)
10893 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : offsetForRemoval should be >=0 !");
10894 std::set<int> s(idsToRemoveBg,idsToRemoveEnd);
10895 int nbOfGrps=arrIndx->getNumberOfTuples()-1;
10896 int *arrIPtr=arrIndx->getPointer();
10898 int previousArrI=0;
10899 const int *arrPtr=arr->getConstPointer();
10900 std::vector<int> arrOut;//no utility to switch to DataArrayInt because copy always needed
10901 for(int i=0;i<nbOfGrps;i++,arrIPtr++)
10903 if(*arrIPtr-previousArrI>offsetForRemoval)
10905 for(const int *work=arrPtr+previousArrI+offsetForRemoval;work!=arrPtr+*arrIPtr;work++)
10907 if(s.find(*work)==s.end())
10908 arrOut.push_back(*work);
10911 previousArrI=*arrIPtr;
10912 *arrIPtr=(int)arrOut.size();
10914 if(arr->getNumberOfTuples()==(int)arrOut.size())
10916 arr->alloc((int)arrOut.size(),1);
10917 std::copy(arrOut.begin(),arrOut.end(),arr->getPointer());
10922 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
10923 * (\ref numbering-indirect).
10924 * This method returns the result of the extraction ( specified by a set of ids in [\b idsOfSelectBg , \b idsOfSelectEnd ) ).
10925 * The selection of extraction is done standardly in new2old format.
10926 * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
10928 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
10929 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
10930 * \param [in] arrIn arr origin array from which the extraction will be done.
10931 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
10932 * \param [out] arrOut the resulting array
10933 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
10934 * \sa MEDCouplingUMesh::ExtractFromIndexedArraysSlice
10936 void MEDCouplingUMesh::ExtractFromIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
10937 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
10939 if(!arrIn || !arrIndxIn)
10940 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input pointer is NULL !");
10941 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
10942 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
10943 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input arrays must have exactly one component !");
10944 std::size_t sz=std::distance(idsOfSelectBg,idsOfSelectEnd);
10945 const int *arrInPtr=arrIn->getConstPointer();
10946 const int *arrIndxPtr=arrIndxIn->getConstPointer();
10947 int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
10949 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
10950 int maxSizeOfArr=arrIn->getNumberOfTuples();
10951 MCAuto<DataArrayInt> arro=DataArrayInt::New();
10952 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
10953 arrIo->alloc((int)(sz+1),1);
10954 const int *idsIt=idsOfSelectBg;
10955 int *work=arrIo->getPointer();
10958 for(std::size_t i=0;i<sz;i++,work++,idsIt++)
10960 if(*idsIt>=0 && *idsIt<nbOfGrps)
10961 lgth+=arrIndxPtr[*idsIt+1]-arrIndxPtr[*idsIt];
10964 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " ! Must be in [0," << nbOfGrps << ") !";
10965 throw INTERP_KERNEL::Exception(oss.str().c_str());
10971 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " and at this pos arrIndxIn[" << *idsIt;
10972 oss << "+1]-arrIndxIn[" << *idsIt << "] < 0 ! The input index array is bugged !";
10973 throw INTERP_KERNEL::Exception(oss.str().c_str());
10976 arro->alloc(lgth,1);
10977 work=arro->getPointer();
10978 idsIt=idsOfSelectBg;
10979 for(std::size_t i=0;i<sz;i++,idsIt++)
10981 if(arrIndxPtr[*idsIt]>=0 && arrIndxPtr[*idsIt+1]<=maxSizeOfArr)
10982 work=std::copy(arrInPtr+arrIndxPtr[*idsIt],arrInPtr+arrIndxPtr[*idsIt+1],work);
10985 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " arrIndx[" << *idsIt << "] must be >= 0 and arrIndx[";
10986 oss << *idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
10987 throw INTERP_KERNEL::Exception(oss.str().c_str());
10990 arrOut=arro.retn();
10991 arrIndexOut=arrIo.retn();
10995 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
10996 * (\ref numbering-indirect).
10997 * This method returns the result of the extraction ( specified by a set of ids with a slice given by \a idsOfSelectStart, \a idsOfSelectStop and \a idsOfSelectStep ).
10998 * The selection of extraction is done standardly in new2old format.
10999 * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
11001 * \param [in] idsOfSelectStart begin of set of ids of the input extraction (included)
11002 * \param [in] idsOfSelectStop end of set of ids of the input extraction (excluded)
11003 * \param [in] idsOfSelectStep
11004 * \param [in] arrIn arr origin array from which the extraction will be done.
11005 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11006 * \param [out] arrOut the resulting array
11007 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11008 * \sa MEDCouplingUMesh::ExtractFromIndexedArrays
11010 void MEDCouplingUMesh::ExtractFromIndexedArraysSlice(int idsOfSelectStart, int idsOfSelectStop, int idsOfSelectStep, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11011 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11013 if(!arrIn || !arrIndxIn)
11014 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input pointer is NULL !");
11015 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
11016 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
11017 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input arrays must have exactly one component !");
11018 int sz=DataArrayInt::GetNumberOfItemGivenBESRelative(idsOfSelectStart,idsOfSelectStop,idsOfSelectStep,"MEDCouplingUMesh::ExtractFromIndexedArraysSlice : Input slice ");
11019 const int *arrInPtr=arrIn->getConstPointer();
11020 const int *arrIndxPtr=arrIndxIn->getConstPointer();
11021 int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
11023 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
11024 int maxSizeOfArr=arrIn->getNumberOfTuples();
11025 MCAuto<DataArrayInt> arro=DataArrayInt::New();
11026 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11027 arrIo->alloc((int)(sz+1),1);
11028 int idsIt=idsOfSelectStart;
11029 int *work=arrIo->getPointer();
11032 for(int i=0;i<sz;i++,work++,idsIt+=idsOfSelectStep)
11034 if(idsIt>=0 && idsIt<nbOfGrps)
11035 lgth+=arrIndxPtr[idsIt+1]-arrIndxPtr[idsIt];
11038 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " ! Must be in [0," << nbOfGrps << ") !";
11039 throw INTERP_KERNEL::Exception(oss.str().c_str());
11045 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " and at this pos arrIndxIn[" << idsIt;
11046 oss << "+1]-arrIndxIn[" << idsIt << "] < 0 ! The input index array is bugged !";
11047 throw INTERP_KERNEL::Exception(oss.str().c_str());
11050 arro->alloc(lgth,1);
11051 work=arro->getPointer();
11052 idsIt=idsOfSelectStart;
11053 for(int i=0;i<sz;i++,idsIt+=idsOfSelectStep)
11055 if(arrIndxPtr[idsIt]>=0 && arrIndxPtr[idsIt+1]<=maxSizeOfArr)
11056 work=std::copy(arrInPtr+arrIndxPtr[idsIt],arrInPtr+arrIndxPtr[idsIt+1],work);
11059 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " arrIndx[" << idsIt << "] must be >= 0 and arrIndx[";
11060 oss << idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
11061 throw INTERP_KERNEL::Exception(oss.str().c_str());
11064 arrOut=arro.retn();
11065 arrIndexOut=arrIo.retn();
11069 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11070 * This method builds an output pair (\b arrOut,\b arrIndexOut) that is a copy from \b arrIn for all cell ids \b not \b in [ \b idsOfSelectBg , \b idsOfSelectEnd ) and for
11071 * cellIds \b in [ \b idsOfSelectBg , \b idsOfSelectEnd ) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
11072 * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
11074 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
11075 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
11076 * \param [in] arrIn arr origin array from which the extraction will be done.
11077 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11078 * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg, \b idsOfSelectEnd )
11079 * \param [in] srcArrIndex index array of \b srcArr
11080 * \param [out] arrOut the resulting array
11081 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11083 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
11085 void MEDCouplingUMesh::SetPartOfIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11086 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
11087 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11089 if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11090 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArrays : presence of null pointer in input parameter !");
11091 MCAuto<DataArrayInt> arro=DataArrayInt::New();
11092 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11093 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11094 std::vector<bool> v(nbOfTuples,true);
11096 const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11097 const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11098 for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
11100 if(*it>=0 && *it<nbOfTuples)
11103 offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[*it+1]-arrIndxInPtr[*it]);
11107 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArrays : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
11108 throw INTERP_KERNEL::Exception(oss.str().c_str());
11111 srcArrIndexPtr=srcArrIndex->getConstPointer();
11112 arrIo->alloc(nbOfTuples+1,1);
11113 arro->alloc(arrIn->getNumberOfTuples()+offset,1);
11114 const int *arrInPtr=arrIn->getConstPointer();
11115 const int *srcArrPtr=srcArr->getConstPointer();
11116 int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
11117 int *arroPtr=arro->getPointer();
11118 for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
11122 arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
11123 *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
11127 std::size_t pos=std::distance(idsOfSelectBg,std::find(idsOfSelectBg,idsOfSelectEnd,ii));
11128 arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
11129 *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
11132 arrOut=arro.retn();
11133 arrIndexOut=arrIo.retn();
11137 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11138 * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
11140 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
11141 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
11142 * \param [in,out] arrInOut arr origin array from which the extraction will be done.
11143 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11144 * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg , \b idsOfSelectEnd )
11145 * \param [in] srcArrIndex index array of \b srcArr
11147 * \sa MEDCouplingUMesh::SetPartOfIndexedArrays
11149 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(const int *idsOfSelectBg, const int *idsOfSelectEnd, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
11150 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
11152 if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11153 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : presence of null pointer in input parameter !");
11154 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11155 const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11156 const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11157 int *arrInOutPtr=arrInOut->getPointer();
11158 const int *srcArrPtr=srcArr->getConstPointer();
11159 for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
11161 if(*it>=0 && *it<nbOfTuples)
11163 if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[*it+1]-arrIndxInPtr[*it])
11164 std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[*it]);
11167 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : On pos #" << std::distance(idsOfSelectBg,it) << " id (idsOfSelectBg[" << std::distance(idsOfSelectBg,it)<< "]) is " << *it << " arrIndxIn[id+1]-arrIndxIn[id]!=srcArrIndex[pos+1]-srcArrIndex[pos] !";
11168 throw INTERP_KERNEL::Exception(oss.str().c_str());
11173 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
11174 throw INTERP_KERNEL::Exception(oss.str().c_str());
11180 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
11181 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
11182 * This method start from id 0 that will be contained in output DataArrayInt. It searches then all neighbors of id0 looking at arrIn[arrIndxIn[0]:arrIndxIn[0+1]].
11183 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
11184 * A negative value in \b arrIn means that it is ignored.
11185 * This method is useful to see if a mesh is contiguous regarding its connectivity. If it is not the case the size of returned array is different from arrIndxIn->getNumberOfTuples()-1.
11187 * \param [in] arrIn arr origin array from which the extraction will be done.
11188 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11189 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
11190 * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
11192 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn)
11194 int seed=0,nbOfDepthPeelingPerformed=0;
11195 return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
11199 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
11200 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
11201 * This method start from id 0 that will be contained in output DataArrayInt. It searches then all neighbors of id0 regarding arrIn[arrIndxIn[0]:arrIndxIn[0+1]].
11202 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
11203 * A negative value in \b arrIn means that it is ignored.
11204 * This method is useful to see if a mesh is contiguous regarding its connectivity. If it is not the case the size of returned array is different from arrIndxIn->getNumberOfTuples()-1.
11205 * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
11206 * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
11207 * \param [in] arrIn arr origin array from which the extraction will be done.
11208 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11209 * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
11210 * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
11211 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
11212 * \sa MEDCouplingUMesh::partitionBySpreadZone
11214 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed)
11216 nbOfDepthPeelingPerformed=0;
11218 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
11219 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11222 DataArrayInt *ret=DataArrayInt::New(); ret->alloc(0,1);
11226 std::vector<bool> fetched(nbOfTuples,false);
11227 return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
11230 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg(std::vector<bool>& fetched, const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed)
11232 nbOfDepthPeelingPerformed=0;
11233 if(!seedBg || !seedEnd || !arrIn || !arrIndxIn)
11234 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg : some input pointer is NULL !");
11235 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11236 std::vector<bool> fetched2(nbOfTuples,false);
11238 for(const int *seedElt=seedBg;seedElt!=seedEnd;seedElt++,i++)
11240 if(*seedElt>=0 && *seedElt<nbOfTuples)
11241 { fetched[*seedElt]=true; fetched2[*seedElt]=true; }
11243 { std::ostringstream oss; oss << "MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg : At pos #" << i << " of seeds value is " << *seedElt << "! Should be in [0," << nbOfTuples << ") !"; throw INTERP_KERNEL::Exception(oss.str().c_str()); }
11245 const int *arrInPtr=arrIn->getConstPointer();
11246 const int *arrIndxPtr=arrIndxIn->getConstPointer();
11247 int targetNbOfDepthPeeling=nbOfDepthPeeling!=-1?nbOfDepthPeeling:std::numeric_limits<int>::max();
11248 std::vector<int> idsToFetch1(seedBg,seedEnd);
11249 std::vector<int> idsToFetch2;
11250 std::vector<int> *idsToFetch=&idsToFetch1;
11251 std::vector<int> *idsToFetchOther=&idsToFetch2;
11252 while(!idsToFetch->empty() && nbOfDepthPeelingPerformed<targetNbOfDepthPeeling)
11254 for(std::vector<int>::const_iterator it=idsToFetch->begin();it!=idsToFetch->end();it++)
11255 for(const int *it2=arrInPtr+arrIndxPtr[*it];it2!=arrInPtr+arrIndxPtr[*it+1];it2++)
11257 { fetched[*it2]=true; fetched2[*it2]=true; idsToFetchOther->push_back(*it2); }
11258 std::swap(idsToFetch,idsToFetchOther);
11259 idsToFetchOther->clear();
11260 nbOfDepthPeelingPerformed++;
11262 int lgth=(int)std::count(fetched2.begin(),fetched2.end(),true);
11264 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(lgth,1);
11265 int *retPtr=ret->getPointer();
11266 for(std::vector<bool>::const_iterator it=fetched2.begin();it!=fetched2.end();it++,i++)
11273 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11274 * This method builds an output pair (\b arrOut,\b arrIndexOut) that is a copy from \b arrIn for all cell ids \b not \b in [ \b idsOfSelectBg , \b idsOfSelectEnd ) and for
11275 * cellIds \b in [\b idsOfSelectBg, \b idsOfSelectEnd) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
11276 * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
11278 * \param [in] start begin of set of ids of the input extraction (included)
11279 * \param [in] end end of set of ids of the input extraction (excluded)
11280 * \param [in] step step of the set of ids in range mode.
11281 * \param [in] arrIn arr origin array from which the extraction will be done.
11282 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11283 * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
11284 * \param [in] srcArrIndex index array of \b srcArr
11285 * \param [out] arrOut the resulting array
11286 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11288 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx MEDCouplingUMesh::SetPartOfIndexedArrays
11290 void MEDCouplingUMesh::SetPartOfIndexedArraysSlice(int start, int end, int step, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11291 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
11292 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11294 if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11295 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSlice : presence of null pointer in input parameter !");
11296 MCAuto<DataArrayInt> arro=DataArrayInt::New();
11297 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11298 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11300 const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11301 const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11302 int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSlice : ");
11304 for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
11306 if(it>=0 && it<nbOfTuples)
11307 offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[it+1]-arrIndxInPtr[it]);
11310 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
11311 throw INTERP_KERNEL::Exception(oss.str().c_str());
11314 srcArrIndexPtr=srcArrIndex->getConstPointer();
11315 arrIo->alloc(nbOfTuples+1,1);
11316 arro->alloc(arrIn->getNumberOfTuples()+offset,1);
11317 const int *arrInPtr=arrIn->getConstPointer();
11318 const int *srcArrPtr=srcArr->getConstPointer();
11319 int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
11320 int *arroPtr=arro->getPointer();
11321 for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
11323 int pos=DataArray::GetPosOfItemGivenBESRelativeNoThrow(ii,start,end,step);
11326 arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
11327 *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
11331 arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
11332 *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
11335 arrOut=arro.retn();
11336 arrIndexOut=arrIo.retn();
11340 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11341 * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
11343 * \param [in] start begin of set of ids of the input extraction (included)
11344 * \param [in] end end of set of ids of the input extraction (excluded)
11345 * \param [in] step step of the set of ids in range mode.
11346 * \param [in,out] arrInOut arr origin array from which the extraction will be done.
11347 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11348 * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
11349 * \param [in] srcArrIndex index array of \b srcArr
11351 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSlice MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
11353 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(int start, int end, int step, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
11354 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
11356 if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11357 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : presence of null pointer in input parameter !");
11358 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11359 const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11360 const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11361 int *arrInOutPtr=arrInOut->getPointer();
11362 const int *srcArrPtr=srcArr->getConstPointer();
11363 int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : ");
11365 for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
11367 if(it>=0 && it<nbOfTuples)
11369 if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[it+1]-arrIndxInPtr[it])
11370 std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[it]);
11373 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " id (idsOfSelectBg[" << i << "]) is " << it << " arrIndxIn[id+1]-arrIndxIn[id]!=srcArrIndex[pos+1]-srcArrIndex[pos] !";
11374 throw INTERP_KERNEL::Exception(oss.str().c_str());
11379 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
11380 throw INTERP_KERNEL::Exception(oss.str().c_str());
11386 * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
11387 * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
11388 * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
11389 * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
11390 * The sum of measure field of returned mesh is equal to the sum of measure field of this.
11392 * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
11394 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
11396 checkFullyDefined();
11397 int mdim=getMeshDimension();
11398 int spaceDim=getSpaceDimension();
11400 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
11401 std::vector<DataArrayInt *> partition=partitionBySpreadZone();
11402 std::vector< MCAuto<DataArrayInt> > partitionAuto; partitionAuto.reserve(partition.size());
11403 std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayInt> > >(partitionAuto));
11404 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
11405 ret->setCoords(getCoords());
11406 ret->allocateCells((int)partition.size());
11408 for(std::vector<DataArrayInt *>::const_iterator it=partition.begin();it!=partition.end();it++)
11410 MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
11411 MCAuto<DataArrayInt> cell;
11415 cell=tmp->buildUnionOf2DMesh();
11418 cell=tmp->buildUnionOf3DMesh();
11421 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
11424 ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->getConstPointer()+1);
11427 ret->finishInsertingCells();
11432 * This method partitions \b this into contiguous zone.
11433 * This method only needs a well defined connectivity. Coordinates are not considered here.
11434 * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
11436 std::vector<DataArrayInt *> MEDCouplingUMesh::partitionBySpreadZone() const
11438 int nbOfCellsCur=getNumberOfCells();
11439 std::vector<DataArrayInt *> ret;
11440 if(nbOfCellsCur<=0)
11442 DataArrayInt *neigh=0,*neighI=0;
11443 computeNeighborsOfCells(neigh,neighI);
11444 MCAuto<DataArrayInt> neighAuto(neigh),neighIAuto(neighI);
11445 std::vector<bool> fetchedCells(nbOfCellsCur,false);
11446 std::vector< MCAuto<DataArrayInt> > ret2;
11448 while(seed<nbOfCellsCur)
11450 int nbOfPeelPerformed=0;
11451 ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,neigh,neighI,-1,nbOfPeelPerformed));
11452 seed=(int)std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false));
11454 for(std::vector< MCAuto<DataArrayInt> >::iterator it=ret2.begin();it!=ret2.end();it++)
11455 ret.push_back((*it).retn());
11460 * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
11461 * newly allocated DataArrayInt instance with 2 components ready to be interpreted as input of DataArrayInt::findRangeIdForEachTuple method.
11463 * \param [in] code a code with the same format than those returned by MEDCouplingUMesh::getDistributionOfTypes except for the code[3*k+2] that should contain start id of chunck.
11464 * \return a newly allocated DataArrayInt to be managed by the caller.
11465 * \throw In case of \a code has not the right format (typically of size 3*n)
11467 DataArrayInt *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<int>& code)
11469 MCAuto<DataArrayInt> ret=DataArrayInt::New();
11470 std::size_t nb=code.size()/3;
11471 if(code.size()%3!=0)
11472 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
11473 ret->alloc((int)nb,2);
11474 int *retPtr=ret->getPointer();
11475 for(std::size_t i=0;i<nb;i++,retPtr+=2)
11477 retPtr[0]=code[3*i+2];
11478 retPtr[1]=code[3*i+2]+code[3*i+1];
11484 * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
11485 * All cells in \a this are expected to be linear 3D cells.
11486 * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
11487 * It leads to an increase to number of cells.
11488 * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
11489 * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
11490 * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
11492 * \param [in] policy - the policy of splitting that must be in (PLANAR_FACE_5, PLANAR_FACE_6, GENERAL_24, GENERAL_48). The policy will be used only for INTERP_KERNEL::NORM_HEXA8 cells.
11493 * For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
11494 * \param [out] nbOfAdditionalPoints - number of nodes added to \c this->_coords. If > 0 a new coordinates object will be constructed result of the aggregation of the old one and the new points added.
11495 * \param [out] n2oCells - A new instance of DataArrayInt holding, for each new cell,
11496 * an id of old cell producing it. The caller is to delete this array using
11497 * decrRef() as it is no more needed.
11498 * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
11500 * \warning This method operates on each cells in this independantly ! So it can leads to non conform mesh in returned value ! If you expect to have a conform mesh in output
11501 * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
11503 * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
11504 * \throw If \a this is not fully constituted with linear 3D cells.
11505 * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
11507 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayInt *& n2oCells, int& nbOfAdditionalPoints) const
11509 INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
11510 checkConnectivityFullyDefined();
11511 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
11512 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
11513 int nbOfCells(getNumberOfCells()),nbNodes(getNumberOfNodes());
11514 MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
11515 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfCells,1);
11516 int *retPt(ret->getPointer());
11517 MCAuto<DataArrayInt> newConn(DataArrayInt::New()); newConn->alloc(0,1);
11518 MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
11519 const int *oldc(_nodal_connec->begin());
11520 const int *oldci(_nodal_connec_index->begin());
11521 const double *coords(_coords->begin());
11522 for(int i=0;i<nbOfCells;i++,oldci++,retPt++)
11524 std::vector<int> a; std::vector<double> b;
11525 INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
11526 std::size_t nbOfTet(a.size()/4); *retPt=(int)nbOfTet;
11527 const int *aa(&a[0]);
11530 for(std::vector<int>::iterator it=a.begin();it!=a.end();it++)
11532 *it=(-(*(it))-1+nbNodes);
11533 addPts->insertAtTheEnd(b.begin(),b.end());
11534 nbNodes+=(int)b.size()/3;
11536 for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
11537 newConn->insertAtTheEnd(aa,aa+4);
11539 if(!addPts->empty())
11541 addPts->rearrange(3);
11542 nbOfAdditionalPoints=addPts->getNumberOfTuples();
11543 addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
11544 ret0->setCoords(addPts);
11548 nbOfAdditionalPoints=0;
11549 ret0->setCoords(getCoords());
11551 ret0->setNodalConnectivity(newConn);
11553 ret->computeOffsetsFull();
11554 n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
11555 return ret0.retn();
11559 * It is the linear part of MEDCouplingUMesh::split2DCells. Here no additionnal nodes will be added in \b this. So coordinates pointer remain unchanged (is not even touch).
11561 * \sa MEDCouplingUMesh::split2DCells
11563 void MEDCouplingUMesh::split2DCellsLinear(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI)
11565 checkConnectivityFullyDefined();
11566 int ncells(getNumberOfCells()),lgthToReach(getNodalConnectivityArrayLen()+subNodesInSeg->getNumberOfTuples());
11567 MCAuto<DataArrayInt> c(DataArrayInt::New()); c->alloc((std::size_t)lgthToReach);
11568 const int *subPtr(subNodesInSeg->begin()),*subIPtr(subNodesInSegI->begin()),*descPtr(desc->begin()),*descIPtr(descI->begin()),*oldConn(getNodalConnectivity()->begin());
11569 int *cPtr(c->getPointer()),*ciPtr(getNodalConnectivityIndex()->getPointer());
11570 int prevPosOfCi(ciPtr[0]);
11571 for(int i=0;i<ncells;i++,ciPtr++,descIPtr++)
11573 int offset(descIPtr[0]),sz(descIPtr[1]-descIPtr[0]),deltaSz(0);
11574 *cPtr++=(int)INTERP_KERNEL::NORM_POLYGON; *cPtr++=oldConn[prevPosOfCi+1];
11575 for(int j=0;j<sz;j++)
11577 int offset2(subIPtr[descPtr[offset+j]]),sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]);
11578 for(int k=0;k<sz2;k++)
11579 *cPtr++=subPtr[offset2+k];
11581 *cPtr++=oldConn[prevPosOfCi+j+2];
11584 prevPosOfCi=ciPtr[1];
11585 ciPtr[1]=ciPtr[0]+1+sz+deltaSz;//sz==old nb of nodes because (nb of subedges=nb of nodes for polygons)
11588 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCellsLinear : Some of edges to be split are orphan !");
11589 _nodal_connec->decrRef();
11590 _nodal_connec=c.retn(); _types.clear(); _types.insert(INTERP_KERNEL::NORM_POLYGON);
11593 int InternalAddPoint(const INTERP_KERNEL::Edge *e, int id, const double *coo, int startId, int endId, DataArrayDouble& addCoo, int& nodesCnter)
11599 int ret(nodesCnter++);
11601 e->getMiddleOfPoints(coo+2*startId,coo+2*endId,newPt);
11602 addCoo.insertAtTheEnd(newPt,newPt+2);
11607 int InternalAddPointOriented(const INTERP_KERNEL::Edge *e, int id, const double *coo, int startId, int endId, DataArrayDouble& addCoo, int& nodesCnter)
11613 int ret(nodesCnter++);
11615 e->getMiddleOfPointsOriented(coo+2*startId,coo+2*endId,newPt);
11616 addCoo.insertAtTheEnd(newPt,newPt+2);
11624 void EnterTheResultOf2DCellFirst(const INTERP_KERNEL::Edge *e, int start, int stp, int nbOfEdges, bool linOrArc, const double *coords, const int *connBg, int offset, DataArrayInt *newConnOfCell, DataArrayDouble *appendedCoords, std::vector<int>& middles)
11627 int trueStart(start>=0?start:nbOfEdges+start);
11628 tmp[0]=linOrArc?(int)INTERP_KERNEL::NORM_QPOLYG:(int)INTERP_KERNEL::NORM_POLYGON; tmp[1]=connBg[trueStart]; tmp[2]=connBg[stp];
11629 newConnOfCell->insertAtTheEnd(tmp,tmp+3);
11634 int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11635 InternalAddPointOriented(e,-1,coords,tmp[1],tmp[2],*appendedCoords,tmp2);
11636 middles.push_back(tmp3+offset);
11639 middles.push_back(connBg[trueStart+nbOfEdges]);
11643 void EnterTheResultOf2DCellMiddle(const INTERP_KERNEL::Edge *e, int start, int stp, int nbOfEdges, bool linOrArc, const double *coords, const int *connBg, int offset, DataArrayInt *newConnOfCell, DataArrayDouble *appendedCoords, std::vector<int>& middles)
11645 int tmpSrt(newConnOfCell->back()),tmpEnd(connBg[stp]);
11646 newConnOfCell->pushBackSilent(tmpEnd);
11651 int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11652 InternalAddPointOriented(e,-1,coords,tmpSrt,tmpEnd,*appendedCoords,tmp2);
11653 middles.push_back(tmp3+offset);
11656 middles.push_back(connBg[start+nbOfEdges]);
11660 void EnterTheResultOf2DCellEnd(const INTERP_KERNEL::Edge *e, int start, int stp, int nbOfEdges, bool linOrArc, const double *coords, const int *connBg, int offset, DataArrayInt *newConnOfCell, DataArrayDouble *appendedCoords, std::vector<int>& middles)
11662 // only the quadratic point to deal with:
11667 int tmpSrt(connBg[start]),tmpEnd(connBg[stp]);
11668 int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11669 InternalAddPointOriented(e,-1,coords,tmpSrt,tmpEnd,*appendedCoords,tmp2);
11670 middles.push_back(tmp3+offset);
11673 middles.push_back(connBg[start+nbOfEdges]);
11680 * Returns true if a colinearization has been found in the given cell. If false is returned the content pushed in \a newConnOfCell is equal to [ \a connBg , \a connEnd ) .
11681 * \a appendedCoords is a DataArrayDouble instance with number of components equal to one (even if the items are pushed by pair).
11683 bool MEDCouplingUMesh::Colinearize2DCell(const double *coords, const int *connBg, const int *connEnd, int offset, DataArrayInt *newConnOfCell, DataArrayDouble *appendedCoords)
11685 std::size_t sz(std::distance(connBg,connEnd));
11686 if(sz<3)//3 because 2+1(for the cell type) and 2 is the minimal number of edges of 2D cell.
11687 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Colinearize2DCell : the input cell has invalid format !");
11689 INTERP_KERNEL::AutoPtr<int> tmpConn(new int[sz]);
11690 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connBg[0]));
11691 unsigned nbs(cm.getNumberOfSons2(connBg+1,sz));
11692 unsigned nbOfHit(0); // number of fusions operated
11693 int posBaseElt(0),posEndElt(0),nbOfTurn(0);
11694 const unsigned int maxNbOfHit = cm.isQuadratic() ? nbs-2 : nbs-3; // a quad cell is authorized to end up with only two edges, a linear one has to keep 3 at least
11695 INTERP_KERNEL::NormalizedCellType typeOfSon;
11696 std::vector<int> middles;
11698 for(;(nbOfTurn+nbOfHit)<nbs;nbOfTurn++)
11700 cm.fillSonCellNodalConnectivity2(posBaseElt,connBg+1,sz,tmpConn,typeOfSon);
11701 std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
11702 INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11703 posEndElt = posBaseElt+1;
11705 // Look backward first: are the final edges of the cells colinear with the first ones?
11706 // This initializes posBaseElt.
11709 for(unsigned i=1;i<nbs && nbOfHit<maxNbOfHit;i++) // 2nd condition is to avoid ending with a cell wih one single edge
11711 cm.fillSonCellNodalConnectivity2(nbs-i,connBg+1,sz,tmpConn,typeOfSon);
11712 INTERP_KERNEL::Edge *eCand(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11713 INTERP_KERNEL::EdgeIntersector *eint(INTERP_KERNEL::Edge::BuildIntersectorWith(e,eCand));
11714 bool isColinear=eint->areColinears();
11727 // Now move forward:
11728 const unsigned fwdStart = (nbOfTurn == 0 ? 0 : posBaseElt); // the first element to be inspected going forward
11729 for(unsigned j=fwdStart+1;j<nbs && nbOfHit<maxNbOfHit;j++) // 2nd condition is to avoid ending with a cell wih one single edge
11731 cm.fillSonCellNodalConnectivity2((int)j,connBg+1,sz,tmpConn,typeOfSon); // get edge #j's connectivity
11732 INTERP_KERNEL::Edge *eCand(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11733 INTERP_KERNEL::EdgeIntersector *eint(INTERP_KERNEL::Edge::BuildIntersectorWith(e,eCand));
11734 bool isColinear(eint->areColinears());
11746 //push [posBaseElt,posEndElt) in newConnOfCell using e
11747 // The if clauses below are (volontary) not mutually exclusive: on a quad cell with 2 edges, the end of the connectivity is also its begining!
11749 // at the begining of the connectivity (insert type)
11750 EnterTheResultOf2DCellFirst(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
11751 else if((nbOfHit+nbOfTurn) != (nbs-1))
11753 EnterTheResultOf2DCellMiddle(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
11754 if ((nbOfHit+nbOfTurn) == (nbs-1))
11755 // at the end (only quad points to deal with)
11756 EnterTheResultOf2DCellEnd(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
11757 posBaseElt=posEndElt;
11760 if(!middles.empty())
11761 newConnOfCell->insertAtTheEnd(middles.begin(),middles.end());
11766 * It is the quadratic part of MEDCouplingUMesh::split2DCells. Here some additionnal nodes can be added at the end of coordinates array object.
11768 * \return int - the number of new nodes created.
11769 * \sa MEDCouplingUMesh::split2DCells
11771 int MEDCouplingUMesh::split2DCellsQuadratic(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *mid, const DataArrayInt *midI)
11773 checkConsistencyLight();
11774 int ncells(getNumberOfCells()),lgthToReach(getNodalConnectivityArrayLen()+2*subNodesInSeg->getNumberOfTuples()),nodesCnt(getNumberOfNodes());
11775 MCAuto<DataArrayInt> c(DataArrayInt::New()); c->alloc((std::size_t)lgthToReach);
11776 MCAuto<DataArrayDouble> addCoo(DataArrayDouble::New()); addCoo->alloc(0,1);
11777 const int *subPtr(subNodesInSeg->begin()),*subIPtr(subNodesInSegI->begin()),*descPtr(desc->begin()),*descIPtr(descI->begin()),*oldConn(getNodalConnectivity()->begin());
11778 const int *midPtr(mid->begin()),*midIPtr(midI->begin());
11779 const double *oldCoordsPtr(getCoords()->begin());
11780 int *cPtr(c->getPointer()),*ciPtr(getNodalConnectivityIndex()->getPointer());
11781 int prevPosOfCi(ciPtr[0]);
11782 for(int i=0;i<ncells;i++,ciPtr++,descIPtr++)
11784 int offset(descIPtr[0]),sz(descIPtr[1]-descIPtr[0]),deltaSz(sz);
11785 for(int j=0;j<sz;j++)
11786 { int sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]); deltaSz+=sz2; }
11787 *cPtr++=(int)INTERP_KERNEL::NORM_QPOLYG; cPtr[0]=oldConn[prevPosOfCi+1];
11788 for(int j=0;j<sz;j++)//loop over subedges of oldConn
11790 int offset2(subIPtr[descPtr[offset+j]]),sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]),offset3(midIPtr[descPtr[offset+j]]);
11794 cPtr[1]=oldConn[prevPosOfCi+2+j];
11795 cPtr[deltaSz]=oldConn[prevPosOfCi+1+j+sz]; cPtr++;
11798 std::vector<INTERP_KERNEL::Node *> ns(3);
11799 ns[0]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+j]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+j]+1]);
11800 ns[1]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+(1+j)%sz]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+(1+j)%sz]+1]);
11801 ns[2]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+sz+j]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+sz+j]+1]);
11802 MCAuto<INTERP_KERNEL::Edge> e(INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(ns));
11803 for(int k=0;k<sz2;k++)//loop over subsplit of current subedge
11805 cPtr[1]=subPtr[offset2+k];
11806 cPtr[deltaSz]=InternalAddPoint(e,midPtr[offset3+k],oldCoordsPtr,cPtr[0],cPtr[1],*addCoo,nodesCnt); cPtr++;
11808 int tmpEnd(oldConn[prevPosOfCi+1+(j+1)%sz]);
11810 { cPtr[1]=tmpEnd; }
11811 cPtr[deltaSz]=InternalAddPoint(e,midPtr[offset3+sz2],oldCoordsPtr,cPtr[0],tmpEnd,*addCoo,nodesCnt); cPtr++;
11813 prevPosOfCi=ciPtr[1]; cPtr+=deltaSz;
11814 ciPtr[1]=ciPtr[0]+1+2*deltaSz;//sz==old nb of nodes because (nb of subedges=nb of nodes for polygons)
11817 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCellsQuadratic : Some of edges to be split are orphan !");
11818 _nodal_connec->decrRef();
11819 _nodal_connec=c.retn(); _types.clear(); _types.insert(INTERP_KERNEL::NORM_QPOLYG);
11820 addCoo->rearrange(2);
11821 MCAuto<DataArrayDouble> coo(DataArrayDouble::Aggregate(getCoords(),addCoo));//info are copied from getCoords() by using Aggregate
11823 return addCoo->getNumberOfTuples();
11826 void MEDCouplingUMesh::ComputeAllTypesInternal(std::set<INTERP_KERNEL::NormalizedCellType>& types, const DataArrayInt *nodalConnec, const DataArrayInt *nodalConnecIndex)
11828 if(nodalConnec && nodalConnecIndex)
11831 const int *conn(nodalConnec->getConstPointer()),*connIndex(nodalConnecIndex->getConstPointer());
11832 int nbOfElem(nodalConnecIndex->getNbOfElems()-1);
11834 for(const int *pt=connIndex;pt!=connIndex+nbOfElem;pt++)
11835 types.insert((INTERP_KERNEL::NormalizedCellType)conn[*pt]);
11839 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
11840 _own_cell(true),_cell_id(-1),_nb_cell(0)
11845 _nb_cell=mesh->getNumberOfCells();
11849 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
11857 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_cell(itc),
11858 _own_cell(false),_cell_id(bg-1),
11865 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
11868 if(_cell_id<_nb_cell)
11877 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
11883 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
11885 return new MEDCouplingUMeshCellByTypeIterator(_mesh);
11888 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
11894 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh, INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_type(type),
11902 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
11908 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
11913 int MEDCouplingUMeshCellEntry::getNumberOfElems() const
11918 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
11920 return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
11923 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
11928 _nb_cell=mesh->getNumberOfCells();
11932 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
11939 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
11941 const int *c=_mesh->getNodalConnectivity()->getConstPointer();
11942 const int *ci=_mesh->getNodalConnectivityIndex()->getConstPointer();
11943 if(_cell_id<_nb_cell)
11945 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
11946 int nbOfElems=(int)std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type)));
11947 int startId=_cell_id;
11948 _cell_id+=nbOfElems;
11949 return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
11955 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
11959 _conn=mesh->getNodalConnectivity()->getPointer();
11960 _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
11964 void MEDCouplingUMeshCell::next()
11966 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
11971 _conn_lgth=_conn_indx[1]-_conn_indx[0];
11974 std::string MEDCouplingUMeshCell::repr() const
11976 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
11978 std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
11980 std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<int>(oss," "));
11984 return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
11987 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
11989 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
11990 return (INTERP_KERNEL::NormalizedCellType)_conn[0];
11992 return INTERP_KERNEL::NORM_ERROR;
11995 const int *MEDCouplingUMeshCell::getAllConn(int& lgth) const
11998 if(_conn_lgth!=NOTICABLE_FIRST_VAL)