1 // Copyright (C) 2007-2016 CEA/DEN, EDF R&D
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 // Author : Anthony Geay (CEA/DEN)
21 #include "MEDCouplingUMesh.hxx"
22 #include "MEDCoupling1GTUMesh.hxx"
23 #include "MEDCouplingMemArray.txx"
24 #include "MEDCouplingFieldDouble.hxx"
25 #include "MEDCouplingSkyLineArray.hxx"
26 #include "CellModel.hxx"
27 #include "VolSurfUser.txx"
28 #include "InterpolationUtils.hxx"
29 #include "PointLocatorAlgos.txx"
31 #include "BBTreeDst.txx"
32 #include "SplitterTetra.hxx"
33 #include "DiameterCalculator.hxx"
34 #include "DirectedBoundingBox.hxx"
35 #include "InterpKernelMatrixTools.hxx"
36 #include "InterpKernelMeshQuality.hxx"
37 #include "InterpKernelCellSimplify.hxx"
38 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
39 #include "InterpKernelAutoPtr.hxx"
40 #include "InterpKernelGeo2DNode.hxx"
41 #include "InterpKernelGeo2DEdgeLin.hxx"
42 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
43 #include "InterpKernelGeo2DQuadraticPolygon.hxx"
52 using namespace MEDCoupling;
54 double MEDCouplingUMesh::EPS_FOR_POLYH_ORIENTATION=1.e-14;
57 const INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::MEDMEM_ORDER[N_MEDMEM_ORDER] = { INTERP_KERNEL::NORM_POINT1, INTERP_KERNEL::NORM_SEG2, INTERP_KERNEL::NORM_SEG3, INTERP_KERNEL::NORM_SEG4, INTERP_KERNEL::NORM_POLYL, INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4, INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_TRI7, INTERP_KERNEL::NORM_QUAD8, INTERP_KERNEL::NORM_QUAD9, INTERP_KERNEL::NORM_POLYGON, INTERP_KERNEL::NORM_QPOLYG, INTERP_KERNEL::NORM_TETRA4, INTERP_KERNEL::NORM_PYRA5, INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXA8, INTERP_KERNEL::NORM_HEXGP12, INTERP_KERNEL::NORM_TETRA10, INTERP_KERNEL::NORM_PYRA13, INTERP_KERNEL::NORM_PENTA15, INTERP_KERNEL::NORM_HEXA20, INTERP_KERNEL::NORM_HEXA27, INTERP_KERNEL::NORM_POLYHED };
58 const int MEDCouplingUMesh::MEDCOUPLING2VTKTYPETRADUCER[INTERP_KERNEL::NORM_MAXTYPE+1]={1,3,21,5,9,7,22,34,23,28,-1,-1,-1,-1,10,14,13,-1,12,-1,24,-1,16,27,-1,26,-1,29,-1,-1,25,42,36,4};
61 MEDCouplingUMesh *MEDCouplingUMesh::New()
63 return new MEDCouplingUMesh;
66 MEDCouplingUMesh *MEDCouplingUMesh::New(const std::string& meshName, int meshDim)
68 MEDCouplingUMesh *ret=new MEDCouplingUMesh;
69 ret->setName(meshName);
70 ret->setMeshDimension(meshDim);
75 * Returns a new MEDCouplingUMesh which is a full copy of \a this one. No data is shared
76 * between \a this and the new mesh.
77 * \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
78 * delete this mesh using decrRef() as it is no more needed.
80 MEDCouplingUMesh *MEDCouplingUMesh::deepCopy() const
87 * Returns a new MEDCouplingUMesh which is a copy of \a this one.
88 * \param [in] recDeepCpy - if \a true, the copy is deep, else all data arrays of \a
89 * this mesh are shared by the new mesh.
90 * \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
91 * delete this mesh using decrRef() as it is no more needed.
93 MEDCouplingUMesh *MEDCouplingUMesh::clone(bool recDeepCpy) const
95 return new MEDCouplingUMesh(*this,recDeepCpy);
99 * This method behaves mostly like MEDCouplingUMesh::deepCopy method, except that only nodal connectivity arrays are deeply copied.
100 * The coordinates are shared between \a this and the returned instance.
102 * \return MEDCouplingUMesh * - A new object instance holding the copy of \a this (deep for connectivity, shallow for coordiantes)
103 * \sa MEDCouplingUMesh::deepCopy
105 MEDCouplingUMesh *MEDCouplingUMesh::deepCopyConnectivityOnly() const
107 checkConnectivityFullyDefined();
108 MCAuto<MEDCouplingUMesh> ret=clone(false);
109 MCAuto<DataArrayInt> c(getNodalConnectivity()->deepCopy()),ci(getNodalConnectivityIndex()->deepCopy());
110 ret->setConnectivity(c,ci);
114 void MEDCouplingUMesh::shallowCopyConnectivityFrom(const MEDCouplingPointSet *other)
117 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is null !");
118 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
120 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is not an MEDCouplingUMesh instance !");
121 MEDCouplingUMesh *otherC2=const_cast<MEDCouplingUMesh *>(otherC);//sorry :(
122 setConnectivity(otherC2->getNodalConnectivity(),otherC2->getNodalConnectivityIndex(),true);
125 std::size_t MEDCouplingUMesh::getHeapMemorySizeWithoutChildren() const
127 std::size_t ret(MEDCouplingPointSet::getHeapMemorySizeWithoutChildren());
131 std::vector<const BigMemoryObject *> MEDCouplingUMesh::getDirectChildrenWithNull() const
133 std::vector<const BigMemoryObject *> ret(MEDCouplingPointSet::getDirectChildrenWithNull());
134 ret.push_back(_nodal_connec);
135 ret.push_back(_nodal_connec_index);
139 void MEDCouplingUMesh::updateTime() const
141 MEDCouplingPointSet::updateTime();
144 updateTimeWith(*_nodal_connec);
146 if(_nodal_connec_index)
148 updateTimeWith(*_nodal_connec_index);
152 MEDCouplingUMesh::MEDCouplingUMesh():_mesh_dim(-2),_nodal_connec(0),_nodal_connec_index(0)
157 * Checks if \a this mesh is well defined. If no exception is thrown by this method,
158 * then \a this mesh is most probably is writable, exchangeable and available for most
159 * of algorithms. When a mesh is constructed from scratch, it is a good habit to call
160 * this method to check that all is in order with \a this mesh.
161 * \throw If the mesh dimension is not set.
162 * \throw If the coordinates array is not set (if mesh dimension != -1 ).
163 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
164 * \throw If the connectivity data array has more than one component.
165 * \throw If the connectivity data array has a named component.
166 * \throw If the connectivity index data array has more than one component.
167 * \throw If the connectivity index data array has a named component.
169 void MEDCouplingUMesh::checkConsistencyLight() const
172 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
174 MEDCouplingPointSet::checkConsistencyLight();
175 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
177 if((int)INTERP_KERNEL::CellModel::GetCellModel(*iter).getDimension()!=_mesh_dim)
179 std::ostringstream message;
180 message << "Mesh invalid because dimension is " << _mesh_dim << " and there is presence of cell(s) with type " << (*iter);
181 throw INTERP_KERNEL::Exception(message.str().c_str());
186 if(_nodal_connec->getNumberOfComponents()!=1)
187 throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to be with number of components set to one !");
188 if(_nodal_connec->getInfoOnComponent(0)!="")
189 throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to have no info on its single component !");
193 throw INTERP_KERNEL::Exception("Nodal connectivity array is not defined !");
194 if(_nodal_connec_index)
196 if(_nodal_connec_index->getNumberOfComponents()!=1)
197 throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to be with number of components set to one !");
198 if(_nodal_connec_index->getInfoOnComponent(0)!="")
199 throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to have no info on its single component !");
203 throw INTERP_KERNEL::Exception("Nodal connectivity index array is not defined !");
207 * Checks if \a this mesh is well defined. If no exception is thrown by this method,
208 * then \a this mesh is most probably is writable, exchangeable and available for all
209 * algorithms. <br> In addition to the checks performed by checkConsistencyLight(), this
210 * method thoroughly checks the nodal connectivity.
211 * \param [in] eps - a not used parameter.
212 * \throw If the mesh dimension is not set.
213 * \throw If the coordinates array is not set (if mesh dimension != -1 ).
214 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
215 * \throw If the connectivity data array has more than one component.
216 * \throw If the connectivity data array has a named component.
217 * \throw If the connectivity index data array has more than one component.
218 * \throw If the connectivity index data array has a named component.
219 * \throw If number of nodes defining an element does not correspond to the type of element.
220 * \throw If the nodal connectivity includes an invalid node id.
222 void MEDCouplingUMesh::checkConsistency(double eps) const
224 checkConsistencyLight();
227 int meshDim=getMeshDimension();
228 int nbOfNodes=getNumberOfNodes();
229 int nbOfCells=getNumberOfCells();
230 const int *ptr=_nodal_connec->getConstPointer();
231 const int *ptrI=_nodal_connec_index->getConstPointer();
232 for(int i=0;i<nbOfCells;i++)
234 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)ptr[ptrI[i]]);
235 if((int)cm.getDimension()!=meshDim)
237 std::ostringstream oss;
238 oss << "MEDCouplingUMesh::checkConsistency : cell << #" << i<< " with type Type " << cm.getRepr() << " in 'this' whereas meshdim == " << meshDim << " !";
239 throw INTERP_KERNEL::Exception(oss.str());
241 int nbOfNodesInCell=ptrI[i+1]-ptrI[i]-1;
243 if(nbOfNodesInCell!=(int)cm.getNumberOfNodes())
245 std::ostringstream oss;
246 oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with static Type '" << cm.getRepr() << "' has " << cm.getNumberOfNodes();
247 oss << " nodes whereas in connectivity there is " << nbOfNodesInCell << " nodes ! Looks very bad !";
248 throw INTERP_KERNEL::Exception(oss.str());
250 if(cm.isQuadratic() && cm.isDynamic() && meshDim == 2)
251 if (nbOfNodesInCell % 2 || nbOfNodesInCell < 4)
253 std::ostringstream oss;
254 oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with quadratic type '" << cm.getRepr() << "' has " << nbOfNodesInCell;
255 oss << " nodes. This should be even, and greater or equal than 4!! Looks very bad!";
256 throw INTERP_KERNEL::Exception(oss.str());
258 for(const int *w=ptr+ptrI[i]+1;w!=ptr+ptrI[i+1];w++)
263 if(nodeId>=nbOfNodes)
265 std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " whereas there are only " << nbOfNodes << " nodes in the mesh !";
266 throw INTERP_KERNEL::Exception(oss.str());
271 std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " in connectivity ! sounds bad !";
272 throw INTERP_KERNEL::Exception(oss.str());
276 if((INTERP_KERNEL::NormalizedCellType)(ptr[ptrI[i]])!=INTERP_KERNEL::NORM_POLYHED)
278 std::ostringstream oss; oss << "Cell #" << i << " is built with node #-1 in connectivity ! sounds bad !";
279 throw INTERP_KERNEL::Exception(oss.str());
287 * Sets dimension of \a this mesh. The mesh dimension in general depends on types of
288 * elements contained in the mesh. For more info on the mesh dimension see
289 * \ref MEDCouplingUMeshPage.
290 * \param [in] meshDim - a new mesh dimension.
291 * \throw If \a meshDim is invalid. A valid range is <em> -1 <= meshDim <= 3</em>.
293 void MEDCouplingUMesh::setMeshDimension(int meshDim)
295 if(meshDim<-1 || meshDim>3)
296 throw INTERP_KERNEL::Exception("Invalid meshDim specified ! Must be greater or equal to -1 and lower or equal to 3 !");
302 * Allocates memory to store an estimation of the given number of cells. The closer is the estimation to the number of cells effectively inserted,
303 * the less will the library need to reallocate memory. If the number of cells to be inserted is not known simply put 0 to this parameter.
304 * If a nodal connectivity previouly existed before the call of this method, it will be reset.
306 * \param [in] nbOfCells - estimation of the number of cell \a this mesh will contain.
308 * \if ENABLE_EXAMPLES
309 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
310 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
313 void MEDCouplingUMesh::allocateCells(int nbOfCells)
316 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::allocateCells : the input number of cells should be >= 0 !");
317 if(_nodal_connec_index)
319 _nodal_connec_index->decrRef();
323 _nodal_connec->decrRef();
325 _nodal_connec_index=DataArrayInt::New();
326 _nodal_connec_index->reserve(nbOfCells+1);
327 _nodal_connec_index->pushBackSilent(0);
328 _nodal_connec=DataArrayInt::New();
329 _nodal_connec->reserve(2*nbOfCells);
335 * Appends a cell to the connectivity array. For deeper understanding what is
336 * happening see \ref MEDCouplingUMeshNodalConnectivity.
337 * \param [in] type - type of cell to add.
338 * \param [in] size - number of nodes constituting this cell.
339 * \param [in] nodalConnOfCell - the connectivity of the cell to add.
341 * \if ENABLE_EXAMPLES
342 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
343 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
346 void MEDCouplingUMesh::insertNextCell(INTERP_KERNEL::NormalizedCellType type, int size, const int *nodalConnOfCell)
348 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
349 if(_nodal_connec_index==0)
350 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::insertNextCell : nodal connectivity not set ! invoke allocateCells before calling insertNextCell !");
351 if((int)cm.getDimension()==_mesh_dim)
354 if(size!=(int)cm.getNumberOfNodes())
356 std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : Trying to push a " << cm.getRepr() << " cell with a size of " << size;
357 oss << " ! Expecting " << cm.getNumberOfNodes() << " !";
358 throw INTERP_KERNEL::Exception(oss.str());
360 int idx=_nodal_connec_index->back();
362 _nodal_connec_index->pushBackSilent(val);
363 _nodal_connec->writeOnPlace(idx,type,nodalConnOfCell,size);
368 std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : cell type " << cm.getRepr() << " has a dimension " << cm.getDimension();
369 oss << " whereas Mesh Dimension of current UMesh instance is set to " << _mesh_dim << " ! Please invoke \"setMeshDimension\" method before or invoke ";
370 oss << "\"MEDCouplingUMesh::New\" static method with 2 parameters name and meshDimension !";
371 throw INTERP_KERNEL::Exception(oss.str());
376 * Compacts data arrays to release unused memory. This method is to be called after
377 * finishing cell insertion using \a this->insertNextCell().
379 * \if ENABLE_EXAMPLES
380 * \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
381 * \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
384 void MEDCouplingUMesh::finishInsertingCells()
386 _nodal_connec->pack();
387 _nodal_connec_index->pack();
388 _nodal_connec->declareAsNew();
389 _nodal_connec_index->declareAsNew();
394 * Entry point for iteration over cells of this. Warning the returned cell iterator should be deallocated.
395 * Useful for python users.
397 MEDCouplingUMeshCellIterator *MEDCouplingUMesh::cellIterator()
399 return new MEDCouplingUMeshCellIterator(this);
403 * Entry point for iteration over cells groups geo types per geotypes. Warning the returned cell iterator should be deallocated.
404 * If \a this is not so that that cells are grouped by geo types this method will throw an exception.
405 * In this case MEDCouplingUMesh::sortCellsInMEDFileFrmt or MEDCouplingUMesh::rearrange2ConsecutiveCellTypes methods for example can be called before invoking this method.
406 * Useful for python users.
408 MEDCouplingUMeshCellByTypeEntry *MEDCouplingUMesh::cellsByType()
410 if(!checkConsecutiveCellTypes())
411 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::cellsByType : this mesh is not sorted by type !");
412 return new MEDCouplingUMeshCellByTypeEntry(this);
416 * Returns a set of all cell types available in \a this mesh.
417 * \return std::set<INTERP_KERNEL::NormalizedCellType> - the set of cell types.
418 * \warning this method does not throw any exception even if \a this is not defined.
419 * \sa MEDCouplingUMesh::getAllGeoTypesSorted
421 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypes() const
427 * This method returns the sorted list of geometric types in \a this.
428 * Sorted means in the same order than the cells in \a this. A single entry in return vector means the maximal chunk of consecutive cells in \a this
429 * having the same geometric type. So a same geometric type can appear more than once if the cells are not sorted per geometric type.
431 * \throw if connectivity in \a this is not correctly defined.
433 * \sa MEDCouplingMesh::getAllGeoTypes
435 std::vector<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypesSorted() const
437 std::vector<INTERP_KERNEL::NormalizedCellType> ret;
438 checkConnectivityFullyDefined();
439 int nbOfCells(getNumberOfCells());
442 if(getNodalConnectivityArrayLen()<1)
443 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAllGeoTypesSorted : the connectivity in this seems invalid !");
444 const int *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin());
445 ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci++]);
446 for(int i=1;i<nbOfCells;i++,ci++)
447 if(ret.back()!=((INTERP_KERNEL::NormalizedCellType)c[*ci]))
448 ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci]);
453 * This method is a method that compares \a this and \a other.
454 * This method compares \b all attributes, even names and component names.
456 bool MEDCouplingUMesh::isEqualIfNotWhy(const MEDCouplingMesh *other, double prec, std::string& reason) const
459 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isEqualIfNotWhy : input other pointer is null !");
460 std::ostringstream oss; oss.precision(15);
461 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
464 reason="mesh given in input is not castable in MEDCouplingUMesh !";
467 if(!MEDCouplingPointSet::isEqualIfNotWhy(other,prec,reason))
469 if(_mesh_dim!=otherC->_mesh_dim)
471 oss << "umesh dimension mismatch : this mesh dimension=" << _mesh_dim << " other mesh dimension=" << otherC->_mesh_dim;
475 if(_types!=otherC->_types)
477 oss << "umesh geometric type mismatch :\nThis geometric types are :";
478 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
479 { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
480 oss << "\nOther geometric types are :";
481 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=otherC->_types.begin();iter!=otherC->_types.end();iter++)
482 { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
486 if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
487 if(_nodal_connec==0 || otherC->_nodal_connec==0)
489 reason="Only one UMesh between the two this and other has its nodal connectivity DataArrayInt defined !";
492 if(_nodal_connec!=otherC->_nodal_connec)
493 if(!_nodal_connec->isEqualIfNotWhy(*otherC->_nodal_connec,reason))
495 reason.insert(0,"Nodal connectivity DataArrayInt differ : ");
498 if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
499 if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
501 reason="Only one UMesh between the two this and other has its nodal connectivity index DataArrayInt defined !";
504 if(_nodal_connec_index!=otherC->_nodal_connec_index)
505 if(!_nodal_connec_index->isEqualIfNotWhy(*otherC->_nodal_connec_index,reason))
507 reason.insert(0,"Nodal connectivity index DataArrayInt differ : ");
514 * Checks if data arrays of this mesh (node coordinates, nodal
515 * connectivity of cells, etc) of two meshes are same. Textual data like name etc. are
517 * \param [in] other - the mesh to compare with.
518 * \param [in] prec - precision value used to compare node coordinates.
519 * \return bool - \a true if the two meshes are same.
521 bool MEDCouplingUMesh::isEqualWithoutConsideringStr(const MEDCouplingMesh *other, double prec) const
523 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
526 if(!MEDCouplingPointSet::isEqualWithoutConsideringStr(other,prec))
528 if(_mesh_dim!=otherC->_mesh_dim)
530 if(_types!=otherC->_types)
532 if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
533 if(_nodal_connec==0 || otherC->_nodal_connec==0)
535 if(_nodal_connec!=otherC->_nodal_connec)
536 if(!_nodal_connec->isEqualWithoutConsideringStr(*otherC->_nodal_connec))
538 if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
539 if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
541 if(_nodal_connec_index!=otherC->_nodal_connec_index)
542 if(!_nodal_connec_index->isEqualWithoutConsideringStr(*otherC->_nodal_connec_index))
548 * Checks if \a this and \a other meshes are geometrically equivalent with high
549 * probability, else an exception is thrown. The meshes are considered equivalent if
550 * (1) meshes contain the same number of nodes and the same number of elements of the
551 * same types (2) three cells of the two meshes (first, last and middle) are based
552 * on coincident nodes (with a specified precision).
553 * \param [in] other - the mesh to compare with.
554 * \param [in] prec - the precision used to compare nodes of the two meshes.
555 * \throw If the two meshes do not match.
557 void MEDCouplingUMesh::checkFastEquivalWith(const MEDCouplingMesh *other, double prec) const
559 MEDCouplingPointSet::checkFastEquivalWith(other,prec);
560 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
562 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkFastEquivalWith : Two meshes are not not unstructured !");
566 * Returns the reverse nodal connectivity. The reverse nodal connectivity enumerates
567 * cells each node belongs to.
568 * \warning For speed reasons, this method does not check if node ids in the nodal
569 * connectivity correspond to the size of node coordinates array.
570 * \param [in,out] revNodal - an array holding ids of cells sharing each node.
571 * \param [in,out] revNodalIndx - an array, of length \a this->getNumberOfNodes() + 1,
572 * dividing cell ids in \a revNodal into groups each referring to one
573 * node. Its every element (except the last one) is an index pointing to the
574 * first id of a group of cells. For example cells sharing the node #1 are
575 * described by following range of indices:
576 * [ \a revNodalIndx[1], \a revNodalIndx[2] ) and the cell ids are
577 * \a revNodal[ \a revNodalIndx[1] ], \a revNodal[ \a revNodalIndx[1] + 1], ...
578 * Number of cells sharing the *i*-th node is
579 * \a revNodalIndx[ *i*+1 ] - \a revNodalIndx[ *i* ].
580 * \throw If the coordinates array is not set.
581 * \throw If the nodal connectivity of cells is not defined.
583 * \if ENABLE_EXAMPLES
584 * \ref cpp_mcumesh_getReverseNodalConnectivity "Here is a C++ example".<br>
585 * \ref py_mcumesh_getReverseNodalConnectivity "Here is a Python example".
588 void MEDCouplingUMesh::getReverseNodalConnectivity(DataArrayInt *revNodal, DataArrayInt *revNodalIndx) const
591 int nbOfNodes=getNumberOfNodes();
592 int *revNodalIndxPtr=(int *)malloc((nbOfNodes+1)*sizeof(int));
593 revNodalIndx->useArray(revNodalIndxPtr,true,C_DEALLOC,nbOfNodes+1,1);
594 std::fill(revNodalIndxPtr,revNodalIndxPtr+nbOfNodes+1,0);
595 const int *conn=_nodal_connec->getConstPointer();
596 const int *connIndex=_nodal_connec_index->getConstPointer();
597 int nbOfCells=getNumberOfCells();
598 int nbOfEltsInRevNodal=0;
599 for(int eltId=0;eltId<nbOfCells;eltId++)
601 const int *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
602 const int *endNdlConnOfCurCell=conn+connIndex[eltId+1];
603 for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
604 if(*iter>=0)//for polyhedrons
606 nbOfEltsInRevNodal++;
607 revNodalIndxPtr[(*iter)+1]++;
610 std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<int>());
611 int *revNodalPtr=(int *)malloc((nbOfEltsInRevNodal)*sizeof(int));
612 revNodal->useArray(revNodalPtr,true,C_DEALLOC,nbOfEltsInRevNodal,1);
613 std::fill(revNodalPtr,revNodalPtr+nbOfEltsInRevNodal,-1);
614 for(int eltId=0;eltId<nbOfCells;eltId++)
616 const int *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
617 const int *endNdlConnOfCurCell=conn+connIndex[eltId+1];
618 for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
619 if(*iter>=0)//for polyhedrons
620 *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind2nd(std::equal_to<int>(),-1))=eltId;
626 int MEDCouplingFastNbrer(int id, unsigned nb, const INTERP_KERNEL::CellModel& cm, bool compute, const int *conn1, const int *conn2)
631 int MEDCouplingOrientationSensitiveNbrer(int id, unsigned nb, const INTERP_KERNEL::CellModel& cm, bool compute, const int *conn1, const int *conn2)
637 if(cm.getOrientationStatus(nb,conn1,conn2))
644 class MinusOneSonsGenerator
647 MinusOneSonsGenerator(const INTERP_KERNEL::CellModel& cm):_cm(cm) { }
648 unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfSons2(conn,lgth); }
649 unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillSonCellNodalConnectivity2(sonId,nodalConn,lgth,sonNodalConn,typeOfSon); }
650 static const int DELTA=1;
652 const INTERP_KERNEL::CellModel& _cm;
655 class MinusOneSonsGeneratorBiQuadratic
658 MinusOneSonsGeneratorBiQuadratic(const INTERP_KERNEL::CellModel& cm):_cm(cm) { }
659 unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfSons2(conn,lgth); }
660 unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillSonCellNodalConnectivity4(sonId,nodalConn,lgth,sonNodalConn,typeOfSon); }
661 static const int DELTA=1;
663 const INTERP_KERNEL::CellModel& _cm;
666 class MinusTwoSonsGenerator
669 MinusTwoSonsGenerator(const INTERP_KERNEL::CellModel& cm):_cm(cm) { }
670 unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfEdgesIn3D(conn,lgth); }
671 unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillSonEdgesNodalConnectivity3D(sonId,nodalConn,lgth,sonNodalConn,typeOfSon); }
672 static const int DELTA=2;
674 const INTERP_KERNEL::CellModel& _cm;
677 class MicroEdgesGenerator2D
680 MicroEdgesGenerator2D(const INTERP_KERNEL::CellModel& cm):_cm(cm) { }
681 unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfMicroEdges(); }
682 unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillMicroEdgeNodalConnectivity(sonId,nodalConn,sonNodalConn,typeOfSon); }
683 static const int DELTA=1;
685 const INTERP_KERNEL::CellModel& _cm;
688 class MicroEdgesGenerator3D
691 MicroEdgesGenerator3D(const INTERP_KERNEL::CellModel& cm):_cm(cm) { }
692 unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfMicroEdges(); }
693 unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillMicroEdgeNodalConnectivity(sonId,nodalConn,sonNodalConn,typeOfSon); }
694 static const int DELTA=2;
696 const INTERP_KERNEL::CellModel& _cm;
702 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
703 * this->getMeshDimension(), that bound cells of \a this mesh. In addition arrays
704 * describing correspondence between cells of \a this and the result meshes are
705 * returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending connectivity,
706 * i.e. enumerate cells of the result mesh bounding each cell of \a this mesh. The
707 * arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
708 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
709 * \warning For speed reasons, this method does not check if node ids in the nodal
710 * connectivity correspond to the size of node coordinates array.
711 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
712 * to write this mesh to the MED file, its cells must be sorted using
713 * sortCellsInMEDFileFrmt().
714 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
715 * each cell of \a this mesh.
716 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
717 * dividing cell ids in \a desc into groups each referring to one
718 * cell of \a this mesh. Its every element (except the last one) is an index
719 * pointing to the first id of a group of cells. For example cells of the
720 * result mesh bounding the cell #1 of \a this mesh are described by following
722 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
723 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
724 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
725 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
726 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
727 * by each cell of the result mesh.
728 * \param [in,out] revDescIndx - the array, of length one more than number of cells
729 * in the result mesh,
730 * dividing cell ids in \a revDesc into groups each referring to one
731 * cell of the result mesh the same way as \a descIndx divides \a desc.
732 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
733 * delete this mesh using decrRef() as it is no more needed.
734 * \throw If the coordinates array is not set.
735 * \throw If the nodal connectivity of cells is node defined.
736 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
737 * revDescIndx == NULL.
739 * \if ENABLE_EXAMPLES
740 * \ref cpp_mcumesh_buildDescendingConnectivity "Here is a C++ example".<br>
741 * \ref py_mcumesh_buildDescendingConnectivity "Here is a Python example".
743 * \sa buildDescendingConnectivity2()
745 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
747 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
751 * \a this has to have a mesh dimension equal to 3. If it is not the case an INTERP_KERNEL::Exception will be thrown.
752 * This behaves exactly as MEDCouplingUMesh::buildDescendingConnectivity does except that this method compute directly the transition from mesh dimension 3 to sub edges (dimension 1)
753 * in one shot. That is to say that this method is equivalent to 2 successive calls to MEDCouplingUMesh::buildDescendingConnectivity.
754 * This method returns 4 arrays and a mesh as MEDCouplingUMesh::buildDescendingConnectivity does.
755 * \sa MEDCouplingUMesh::buildDescendingConnectivity
757 MEDCouplingUMesh *MEDCouplingUMesh::explode3DMeshTo1D(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
760 if(getMeshDimension()!=3)
761 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explode3DMeshTo1D : This has to have a mesh dimension to 3 !");
762 return buildDescendingConnectivityGen<MinusTwoSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
766 * This method computes the micro edges constituting each cell in \a this. Micro edge is an edge for non quadratic cells. Micro edge is an half edge for quadratic cells.
767 * This method works for both meshes with mesh dimenstion equal to 2 or 3. Dynamical cells are not supported (polygons, polyhedrons...)
769 * \sa explode3DMeshTo1D, buildDescendingConnectiviy
771 MEDCouplingUMesh *MEDCouplingUMesh::explodeMeshIntoMicroEdges(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
774 switch(getMeshDimension())
777 return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
779 return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
781 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explodeMeshIntoMicroEdges : Only 2D and 3D supported !");
786 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
787 * this->getMeshDimension(), that bound cells of \a this mesh. In
788 * addition arrays describing correspondence between cells of \a this and the result
789 * meshes are returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending
790 * connectivity, i.e. enumerate cells of the result mesh bounding each cell of \a this
791 * mesh. This method differs from buildDescendingConnectivity() in that apart
792 * from cell ids, \a desc returns mutual orientation of cells in \a this and the
793 * result meshes. So a positive id means that order of nodes in corresponding cells
794 * of two meshes is same, and a negative id means a reverse order of nodes. Since a
795 * cell with id #0 can't be negative, the array \a desc returns ids in FORTRAN mode,
796 * i.e. cell ids are one-based.
797 * Arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
798 * i.e. enumerate cells of \a this mesh bounded by each cell of the result mesh.
799 * \warning For speed reasons, this method does not check if node ids in the nodal
800 * connectivity correspond to the size of node coordinates array.
801 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
802 * to write this mesh to the MED file, its cells must be sorted using
803 * sortCellsInMEDFileFrmt().
804 * \param [in,out] desc - the array containing cell ids of the result mesh bounding
805 * each cell of \a this mesh.
806 * \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
807 * dividing cell ids in \a desc into groups each referring to one
808 * cell of \a this mesh. Its every element (except the last one) is an index
809 * pointing to the first id of a group of cells. For example cells of the
810 * result mesh bounding the cell #1 of \a this mesh are described by following
812 * [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
813 * \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
814 * Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
815 * \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
816 * \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
817 * by each cell of the result mesh.
818 * \param [in,out] revDescIndx - the array, of length one more than number of cells
819 * in the result mesh,
820 * dividing cell ids in \a revDesc into groups each referring to one
821 * cell of the result mesh the same way as \a descIndx divides \a desc.
822 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This result mesh
823 * shares the node coordinates array with \a this mesh. The caller is to
824 * delete this mesh using decrRef() as it is no more needed.
825 * \throw If the coordinates array is not set.
826 * \throw If the nodal connectivity of cells is node defined.
827 * \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
828 * revDescIndx == NULL.
830 * \if ENABLE_EXAMPLES
831 * \ref cpp_mcumesh_buildDescendingConnectivity2 "Here is a C++ example".<br>
832 * \ref py_mcumesh_buildDescendingConnectivity2 "Here is a Python example".
834 * \sa buildDescendingConnectivity()
836 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
838 return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingOrientationSensitiveNbrer);
842 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
843 * For speed reasons no check of this will be done. This method calls
844 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
845 * This method lists cell by cell in \b this which are its neighbors. To compute the result
846 * only connectivities are considered.
847 * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
848 * The format of return is hence \ref numbering-indirect.
850 * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly
851 * allocated and should be dealt by the caller. \b neighborsIndx 2nd output
852 * parameter allows to select the right part in this array (\ref numbering-indirect). The number of tuples
853 * is equal to the last values in \b neighborsIndx.
854 * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be
855 * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
857 void MEDCouplingUMesh::computeNeighborsOfCells(DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx) const
859 MCAuto<DataArrayInt> desc=DataArrayInt::New();
860 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
861 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
862 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
863 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
865 ComputeNeighborsOfCellsAdv(desc,descIndx,revDesc,revDescIndx,neighbors,neighborsIndx);
869 * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm
870 * of MEDCouplingUMesh::computeNeighborsOfCells.
871 * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is
872 * typically the case to extract a set a neighbours,
873 * excluding a set of meshdim-1 cells in input descending connectivity.
874 * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx (\ref numbering-indirect) input params are
875 * the result of MEDCouplingUMesh::buildDescendingConnectivity.
876 * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities
878 * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
880 * \param [in] desc descending connectivity array.
881 * \param [in] descIndx descending connectivity index array used to walk through \b desc (\ref numbering-indirect).
882 * \param [in] revDesc reverse descending connectivity array.
883 * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc (\ref numbering-indirect).
884 * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
885 * parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
886 * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
888 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayInt *desc, const DataArrayInt *descIndx, const DataArrayInt *revDesc, const DataArrayInt *revDescIndx,
889 DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx)
891 if(!desc || !descIndx || !revDesc || !revDescIndx)
892 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
893 const int *descPtr=desc->getConstPointer();
894 const int *descIPtr=descIndx->getConstPointer();
895 const int *revDescPtr=revDesc->getConstPointer();
896 const int *revDescIPtr=revDescIndx->getConstPointer();
898 int nbCells=descIndx->getNumberOfTuples()-1;
899 MCAuto<DataArrayInt> out0=DataArrayInt::New();
900 MCAuto<DataArrayInt> out1=DataArrayInt::New(); out1->alloc(nbCells+1,1);
901 int *out1Ptr=out1->getPointer();
903 out0->reserve(desc->getNumberOfTuples());
904 for(int i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
906 for(const int *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
908 std::set<int> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
910 out0->insertAtTheEnd(s.begin(),s.end());
912 *out1Ptr=out0->getNumberOfTuples();
914 neighbors=out0.retn();
915 neighborsIndx=out1.retn();
919 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
920 * For speed reasons no check of this will be done. This method calls
921 * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
922 * This method lists node by node in \b this which are its neighbors. To compute the result
923 * only connectivities are considered.
924 * The neighbor nodes of node having id 'nodeId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
926 * \param [out] neighbors is an array storing all the neighbors of all nodes in \b this. This array
927 * is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
928 * parameter allows to select the right part in this array (\ref numbering-indirect).
929 * The number of tuples is equal to the last values in \b neighborsIndx.
930 * \param [out] neighborsIdx is an array of size this->getNumberOfCells()+1 newly allocated and should
931 * be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
933 void MEDCouplingUMesh::computeNeighborsOfNodes(DataArrayInt *&neighbors, DataArrayInt *&neighborsIdx) const
936 int mdim(getMeshDimension()),nbNodes(getNumberOfNodes());
937 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descIndx(DataArrayInt::New()),revDesc(DataArrayInt::New()),revDescIndx(DataArrayInt::New());
938 MCAuto<MEDCouplingUMesh> mesh1D;
943 mesh1D=explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx);
948 mesh1D=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
953 mesh1D=const_cast<MEDCouplingUMesh *>(this);
959 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2,1] !");
962 desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=0; revDescIndx=0;
963 mesh1D->getReverseNodalConnectivity(desc,descIndx);
964 MCAuto<DataArrayInt> ret0(DataArrayInt::New());
965 ret0->alloc(desc->getNumberOfTuples(),1);
966 int *r0Pt(ret0->getPointer());
967 const int *c1DPtr(mesh1D->getNodalConnectivity()->begin()),*rn(desc->begin()),*rni(descIndx->begin());
968 for(int i=0;i<nbNodes;i++,rni++)
970 for(const int *oneDCellIt=rn+rni[0];oneDCellIt!=rn+rni[1];oneDCellIt++)
971 *r0Pt++=c1DPtr[3*(*oneDCellIt)+1]==i?c1DPtr[3*(*oneDCellIt)+2]:c1DPtr[3*(*oneDCellIt)+1];
973 neighbors=ret0.retn();
974 neighborsIdx=descIndx.retn();
980 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
981 * For speed reasons no check of this will be done.
983 template<class SonsGenerator>
984 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivityGen(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx, DimM1DescNbrer nbrer) const
986 if(!desc || !descIndx || !revDesc || !revDescIndx)
987 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildDescendingConnectivityGen : present of a null pointer in input !");
988 checkConnectivityFullyDefined();
989 int nbOfCells=getNumberOfCells();
990 int nbOfNodes=getNumberOfNodes();
991 MCAuto<DataArrayInt> revNodalIndx=DataArrayInt::New(); revNodalIndx->alloc(nbOfNodes+1,1); revNodalIndx->fillWithZero();
992 int *revNodalIndxPtr=revNodalIndx->getPointer();
993 const int *conn=_nodal_connec->getConstPointer();
994 const int *connIndex=_nodal_connec_index->getConstPointer();
995 std::string name="Mesh constituent of "; name+=getName();
996 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(name,getMeshDimension()-SonsGenerator::DELTA);
997 ret->setCoords(getCoords());
998 ret->allocateCells(2*nbOfCells);
999 descIndx->alloc(nbOfCells+1,1);
1000 MCAuto<DataArrayInt> revDesc2(DataArrayInt::New()); revDesc2->reserve(2*nbOfCells);
1001 int *descIndxPtr=descIndx->getPointer(); *descIndxPtr++=0;
1002 for(int eltId=0;eltId<nbOfCells;eltId++,descIndxPtr++)
1004 int pos=connIndex[eltId];
1005 int posP1=connIndex[eltId+1];
1006 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[pos]);
1007 SonsGenerator sg(cm);
1008 unsigned nbOfSons=sg.getNumberOfSons2(conn+pos+1,posP1-pos-1);
1009 INTERP_KERNEL::AutoPtr<int> tmp=new int[posP1-pos];
1010 for(unsigned i=0;i<nbOfSons;i++)
1012 INTERP_KERNEL::NormalizedCellType cmsId;
1013 unsigned nbOfNodesSon=sg.fillSonCellNodalConnectivity2(i,conn+pos+1,posP1-pos-1,tmp,cmsId);
1014 for(unsigned k=0;k<nbOfNodesSon;k++)
1016 revNodalIndxPtr[tmp[k]+1]++;
1017 ret->insertNextCell(cmsId,nbOfNodesSon,tmp);
1018 revDesc2->pushBackSilent(eltId);
1020 descIndxPtr[0]=descIndxPtr[-1]+(int)nbOfSons;
1022 int nbOfCellsM1=ret->getNumberOfCells();
1023 std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<int>());
1024 MCAuto<DataArrayInt> revNodal=DataArrayInt::New(); revNodal->alloc(revNodalIndx->back(),1);
1025 std::fill(revNodal->getPointer(),revNodal->getPointer()+revNodalIndx->back(),-1);
1026 int *revNodalPtr=revNodal->getPointer();
1027 const int *connM1=ret->getNodalConnectivity()->getConstPointer();
1028 const int *connIndexM1=ret->getNodalConnectivityIndex()->getConstPointer();
1029 for(int eltId=0;eltId<nbOfCellsM1;eltId++)
1031 const int *strtNdlConnOfCurCell=connM1+connIndexM1[eltId]+1;
1032 const int *endNdlConnOfCurCell=connM1+connIndexM1[eltId+1];
1033 for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
1034 if(*iter>=0)//for polyhedrons
1035 *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind2nd(std::equal_to<int>(),-1))=eltId;
1038 DataArrayInt *commonCells=0,*commonCellsI=0;
1039 FindCommonCellsAlg(3,0,ret->getNodalConnectivity(),ret->getNodalConnectivityIndex(),revNodal,revNodalIndx,commonCells,commonCellsI);
1040 MCAuto<DataArrayInt> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1041 const int *commonCellsPtr(commonCells->getConstPointer()),*commonCellsIPtr(commonCellsI->getConstPointer());
1042 int newNbOfCellsM1=-1;
1043 MCAuto<DataArrayInt> o2nM1=DataArrayInt::ConvertIndexArrayToO2N(nbOfCellsM1,commonCells->begin(),
1044 commonCellsI->begin(),commonCellsI->end(),newNbOfCellsM1);
1045 std::vector<bool> isImpacted(nbOfCellsM1,false);
1046 for(const int *work=commonCellsI->begin();work!=commonCellsI->end()-1;work++)
1047 for(int work2=work[0];work2!=work[1];work2++)
1048 isImpacted[commonCellsPtr[work2]]=true;
1049 const int *o2nM1Ptr=o2nM1->getConstPointer();
1050 MCAuto<DataArrayInt> n2oM1=o2nM1->invertArrayO2N2N2OBis(newNbOfCellsM1);
1051 const int *n2oM1Ptr=n2oM1->getConstPointer();
1052 MCAuto<MEDCouplingUMesh> ret2=static_cast<MEDCouplingUMesh *>(ret->buildPartOfMySelf(n2oM1->begin(),n2oM1->end(),true));
1053 ret2->copyTinyInfoFrom(this);
1054 desc->alloc(descIndx->back(),1);
1055 int *descPtr=desc->getPointer();
1056 const INTERP_KERNEL::CellModel& cmsDft=INTERP_KERNEL::CellModel::GetCellModel(INTERP_KERNEL::NORM_POINT1);
1057 for(int i=0;i<nbOfCellsM1;i++,descPtr++)
1060 *descPtr=nbrer(o2nM1Ptr[i],0,cmsDft,false,0,0);
1063 if(i!=n2oM1Ptr[o2nM1Ptr[i]])
1065 const INTERP_KERNEL::CellModel& cms=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connM1[connIndexM1[i]]);
1066 *descPtr=nbrer(o2nM1Ptr[i],connIndexM1[i+1]-connIndexM1[i]-1,cms,true,connM1+connIndexM1[n2oM1Ptr[o2nM1Ptr[i]]]+1,connM1+connIndexM1[i]+1);
1069 *descPtr=nbrer(o2nM1Ptr[i],0,cmsDft,false,0,0);
1072 revDesc->reserve(newNbOfCellsM1);
1073 revDescIndx->alloc(newNbOfCellsM1+1,1);
1074 int *revDescIndxPtr=revDescIndx->getPointer(); *revDescIndxPtr++=0;
1075 const int *revDesc2Ptr=revDesc2->getConstPointer();
1076 for(int i=0;i<newNbOfCellsM1;i++,revDescIndxPtr++)
1078 int oldCellIdM1=n2oM1Ptr[i];
1079 if(!isImpacted[oldCellIdM1])
1081 revDesc->pushBackSilent(revDesc2Ptr[oldCellIdM1]);
1082 revDescIndxPtr[0]=revDescIndxPtr[-1]+1;
1086 for(int j=commonCellsIPtr[0];j<commonCellsIPtr[1];j++)
1087 revDesc->pushBackSilent(revDesc2Ptr[commonCellsPtr[j]]);
1088 revDescIndxPtr[0]=revDescIndxPtr[-1]+commonCellsIPtr[1]-commonCellsIPtr[0];
1096 struct MEDCouplingAccVisit
1098 MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1099 int operator()(int val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1100 int _new_nb_of_nodes;
1106 * Converts specified cells to either polygons (if \a this is a 2D mesh) or
1107 * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an
1108 * array of cell ids. Pay attention that after conversion all algorithms work slower
1109 * with \a this mesh than before conversion. <br> If an exception is thrown during the
1110 * conversion due presence of invalid ids in the array of cells to convert, as a
1111 * result \a this mesh contains some already converted elements. In this case the 2D
1112 * mesh remains valid but 3D mesh becomes \b inconsistent!
1113 * \warning This method can significantly modify the order of geometric types in \a this,
1114 * hence, to write this mesh to the MED file, its cells must be sorted using
1115 * sortCellsInMEDFileFrmt().
1116 * \param [in] cellIdsToConvertBg - the array holding ids of cells to convert.
1117 * \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a
1118 * cellIdsToConvertBg.
1119 * \throw If the coordinates array is not set.
1120 * \throw If the nodal connectivity of cells is node defined.
1121 * \throw If dimension of \a this mesh is not either 2 or 3.
1123 * \if ENABLE_EXAMPLES
1124 * \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".<br>
1125 * \ref py_mcumesh_convertToPolyTypes "Here is a Python example".
1128 void MEDCouplingUMesh::convertToPolyTypes(const int *cellIdsToConvertBg, const int *cellIdsToConvertEnd)
1130 checkFullyDefined();
1131 int dim=getMeshDimension();
1133 throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
1134 int nbOfCells(getNumberOfCells());
1137 const int *connIndex=_nodal_connec_index->getConstPointer();
1138 int *conn=_nodal_connec->getPointer();
1139 for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1141 if(*iter>=0 && *iter<nbOfCells)
1143 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
1144 if(!cm.isQuadratic())
1145 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
1147 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
1151 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1152 oss << " in range [0," << nbOfCells << ") !";
1153 throw INTERP_KERNEL::Exception(oss.str());
1159 int *connIndex(_nodal_connec_index->getPointer());
1160 const int *connOld(_nodal_connec->getConstPointer());
1161 MCAuto<DataArrayInt> connNew(DataArrayInt::New()),connNewI(DataArrayInt::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0);
1162 std::vector<bool> toBeDone(nbOfCells,false);
1163 for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1165 if(*iter>=0 && *iter<nbOfCells)
1166 toBeDone[*iter]=true;
1169 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1170 oss << " in range [0," << nbOfCells << ") !";
1171 throw INTERP_KERNEL::Exception(oss.str());
1174 for(int cellId=0;cellId<nbOfCells;cellId++)
1176 int pos(connIndex[cellId]),posP1(connIndex[cellId+1]);
1177 int lgthOld(posP1-pos-1);
1178 if(toBeDone[cellId])
1180 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connOld[pos]);
1181 unsigned nbOfFaces(cm.getNumberOfSons2(connOld+pos+1,lgthOld));
1182 int *tmp(new int[nbOfFaces*lgthOld+1]);
1183 int *work=tmp; *work++=INTERP_KERNEL::NORM_POLYHED;
1184 for(unsigned j=0;j<nbOfFaces;j++)
1186 INTERP_KERNEL::NormalizedCellType type;
1187 unsigned offset=cm.fillSonCellNodalConnectivity2(j,connOld+pos+1,lgthOld,work,type);
1191 std::size_t newLgth(std::distance(tmp,work)-1);//-1 for last -1
1192 connNew->pushBackValsSilent(tmp,tmp+newLgth);
1193 connNewI->pushBackSilent(connNewI->back()+(int)newLgth);
1198 connNew->pushBackValsSilent(connOld+pos,connOld+posP1);
1199 connNewI->pushBackSilent(connNewI->back()+posP1-pos);
1202 setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind.
1208 * Converts all cells to either polygons (if \a this is a 2D mesh) or
1209 * polyhedrons (if \a this is a 3D mesh).
1210 * \warning As this method is purely for user-friendliness and no optimization is
1211 * done to avoid construction of a useless vector, this method can be costly
1213 * \throw If the coordinates array is not set.
1214 * \throw If the nodal connectivity of cells is node defined.
1215 * \throw If dimension of \a this mesh is not either 2 or 3.
1217 void MEDCouplingUMesh::convertAllToPoly()
1219 int nbOfCells=getNumberOfCells();
1220 std::vector<int> cellIds(nbOfCells);
1221 for(int i=0;i<nbOfCells;i++)
1223 convertToPolyTypes(&cellIds[0],&cellIds[0]+cellIds.size());
1227 * Fixes nodal connectivity of invalid cells of type NORM_POLYHED. This method
1228 * expects that all NORM_POLYHED cells have connectivity similar to that of prismatic
1229 * volumes like NORM_HEXA8, NORM_PENTA6 etc., i.e. the first half of nodes describes a
1230 * base facet of the volume and the second half of nodes describes an opposite facet
1231 * having the same number of nodes as the base one. This method converts such
1232 * connectivity to a valid polyhedral format where connectivity of each facet is
1233 * explicitly described and connectivity of facets are separated by -1. If \a this mesh
1234 * contains a NORM_POLYHED cell with a valid connectivity, or an invalid connectivity is
1235 * not as expected, an exception is thrown and the mesh remains unchanged. Care of
1236 * a correct orientation of the first facet of a polyhedron, else orientation of a
1237 * corrected cell is reverse.<br>
1238 * This method is useful to build an extruded unstructured mesh with polyhedrons as
1239 * it releases the user from boring description of polyhedra connectivity in the valid
1241 * \throw If \a this->getMeshDimension() != 3.
1242 * \throw If \a this->getSpaceDimension() != 3.
1243 * \throw If the nodal connectivity of cells is not defined.
1244 * \throw If the coordinates array is not set.
1245 * \throw If \a this mesh contains polyhedrons with the valid connectivity.
1246 * \throw If \a this mesh contains polyhedrons with odd number of nodes.
1248 * \if ENABLE_EXAMPLES
1249 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
1250 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
1253 void MEDCouplingUMesh::convertExtrudedPolyhedra()
1255 checkFullyDefined();
1256 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1257 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
1258 int nbOfCells=getNumberOfCells();
1259 MCAuto<DataArrayInt> newCi=DataArrayInt::New();
1260 newCi->alloc(nbOfCells+1,1);
1261 int *newci=newCi->getPointer();
1262 const int *ci=_nodal_connec_index->getConstPointer();
1263 const int *c=_nodal_connec->getConstPointer();
1265 for(int i=0;i<nbOfCells;i++)
1267 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1268 if(type==INTERP_KERNEL::NORM_POLYHED)
1270 if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
1272 std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
1273 throw INTERP_KERNEL::Exception(oss.str());
1275 std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
1278 std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron with 1 face but there is a mismatch of number of nodes in face should be even !";
1279 throw INTERP_KERNEL::Exception(oss.str());
1282 newci[i+1]=7*n1+2+newci[i];//6*n1 (nodal length) + n1+2 (number of faces) - 1 (number of '-1' separator is equal to number of faces -1) + 1 (for cell type)
1285 newci[i+1]=(ci[i+1]-ci[i])+newci[i];
1287 MCAuto<DataArrayInt> newC=DataArrayInt::New();
1288 newC->alloc(newci[nbOfCells],1);
1289 int *newc=newC->getPointer();
1290 for(int i=0;i<nbOfCells;i++)
1292 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1293 if(type==INTERP_KERNEL::NORM_POLYHED)
1295 std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
1296 newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
1298 for(std::size_t j=0;j<n1;j++)
1300 newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
1302 newc[n1+5*j+1]=c[ci[i]+1+j];
1303 newc[n1+5*j+2]=c[ci[i]+1+j+n1];
1304 newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
1305 newc[n1+5*j+4]=c[ci[i]+1+(j+1)%n1];
1310 newc=std::copy(c+ci[i],c+ci[i+1],newc);
1312 _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
1313 _nodal_connec->decrRef(); _nodal_connec=newC.retn();
1318 * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D
1319 * mesh) to cells of classical types. This method is opposite to convertToPolyTypes().
1320 * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
1321 * to write this mesh to the MED file, its cells must be sorted using
1322 * sortCellsInMEDFileFrmt().
1323 * \warning Cells (and most notably polyhedrons) must be correctly oriented for this to work
1324 * properly. See orientCorrectlyPolyhedrons() and arePolyhedronsNotCorrectlyOriented().
1325 * \return \c true if at least one cell has been converted, \c false else. In the
1326 * last case the nodal connectivity remains unchanged.
1327 * \throw If the coordinates array is not set.
1328 * \throw If the nodal connectivity of cells is not defined.
1329 * \throw If \a this->getMeshDimension() < 0.
1331 bool MEDCouplingUMesh::unPolyze()
1333 checkFullyDefined();
1334 int mdim=getMeshDimension();
1336 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1339 int nbOfCells=getNumberOfCells();
1342 int initMeshLgth=getNodalConnectivityArrayLen();
1343 int *conn=_nodal_connec->getPointer();
1344 int *index=_nodal_connec_index->getPointer();
1349 for(int i=0;i<nbOfCells;i++)
1351 lgthOfCurCell=index[i+1]-posOfCurCell;
1352 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1353 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1354 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1358 switch(cm.getDimension())
1362 INTERP_KERNEL::AutoPtr<int> tmp=new int[lgthOfCurCell-1];
1363 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(int *)tmp);
1364 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1369 int nbOfFaces,lgthOfPolyhConn;
1370 INTERP_KERNEL::AutoPtr<int> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1371 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1376 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1380 ret=ret || (newType!=type);
1381 conn[newPos]=newType;
1383 posOfCurCell=index[i+1];
1388 std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1389 newPos+=lgthOfCurCell;
1390 posOfCurCell+=lgthOfCurCell;
1394 if(newPos!=initMeshLgth)
1395 _nodal_connec->reAlloc(newPos);
1402 * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1403 * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1404 * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells.
1406 * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not. This epsilon is used to recenter around origin to have maximal
1409 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1411 checkFullyDefined();
1412 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1413 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1414 MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1415 coords->recenterForMaxPrecision(eps);
1417 int nbOfCells=getNumberOfCells();
1418 const int *conn=_nodal_connec->getConstPointer();
1419 const int *index=_nodal_connec_index->getConstPointer();
1420 MCAuto<DataArrayInt> connINew=DataArrayInt::New();
1421 connINew->alloc(nbOfCells+1,1);
1422 int *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1423 MCAuto<DataArrayInt> connNew=DataArrayInt::New(); connNew->alloc(0,1);
1425 for(int i=0;i<nbOfCells;i++,connINewPtr++)
1427 if(conn[index[i]]==(int)INTERP_KERNEL::NORM_POLYHED)
1429 SimplifyPolyhedronCell(eps,coords,conn+index[i],conn+index[i+1],connNew);
1433 connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1434 *connINewPtr=connNew->getNumberOfTuples();
1437 setConnectivity(connNew,connINew,false);
1441 * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1442 * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1443 * the format of the returned DataArrayInt instance.
1445 * \return a newly allocated DataArrayInt sorted ascendingly of fetched node ids.
1446 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1448 DataArrayInt *MEDCouplingUMesh::computeFetchedNodeIds() const
1450 checkConnectivityFullyDefined();
1451 int nbOfCells=getNumberOfCells();
1452 const int *connIndex=_nodal_connec_index->getConstPointer();
1453 const int *conn=_nodal_connec->getConstPointer();
1454 const int *maxEltPt=std::max_element(_nodal_connec->begin(),_nodal_connec->end());
1455 int maxElt=maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1;
1456 std::vector<bool> retS(maxElt,false);
1457 for(int i=0;i<nbOfCells;i++)
1458 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1462 for(int i=0;i<maxElt;i++)
1465 DataArrayInt *ret=DataArrayInt::New();
1467 int *retPtr=ret->getPointer();
1468 for(int i=0;i<maxElt;i++)
1475 * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1476 * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1478 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1480 int nbOfNodes((int)nodeIdsInUse.size()),nbOfCells(getNumberOfCells());
1481 const int *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1482 for(int i=0;i<nbOfCells;i++)
1483 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1486 if(conn[j]<nbOfNodes)
1487 nodeIdsInUse[conn[j]]=true;
1490 std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1491 throw INTERP_KERNEL::Exception(oss.str());
1497 * Finds nodes not used in any cell and returns an array giving a new id to every node
1498 * by excluding the unused nodes, for which the array holds -1. The result array is
1499 * a mapping in "Old to New" mode.
1500 * \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1501 * \return DataArrayInt * - a new instance of DataArrayInt. Its length is \a
1502 * this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1503 * if the node is unused or a new id else. The caller is to delete this
1504 * array using decrRef() as it is no more needed.
1505 * \throw If the coordinates array is not set.
1506 * \throw If the nodal connectivity of cells is not defined.
1507 * \throw If the nodal connectivity includes an invalid id.
1509 * \if ENABLE_EXAMPLES
1510 * \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1511 * \ref py_mcumesh_getNodeIdsInUse "Here is a Python example".
1513 * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1515 DataArrayInt *MEDCouplingUMesh::getNodeIdsInUse(int& nbrOfNodesInUse) const
1518 int nbOfNodes(getNumberOfNodes());
1519 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1520 ret->alloc(nbOfNodes,1);
1521 int *traducer=ret->getPointer();
1522 std::fill(traducer,traducer+nbOfNodes,-1);
1523 int nbOfCells=getNumberOfCells();
1524 const int *connIndex=_nodal_connec_index->getConstPointer();
1525 const int *conn=_nodal_connec->getConstPointer();
1526 for(int i=0;i<nbOfCells;i++)
1527 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1530 if(conn[j]<nbOfNodes)
1531 traducer[conn[j]]=1;
1534 std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i << " presence of node id " << conn[j] << " not in [0," << nbOfNodes << ") !";
1535 throw INTERP_KERNEL::Exception(oss.str());
1538 nbrOfNodesInUse=(int)std::count(traducer,traducer+nbOfNodes,1);
1539 std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1544 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1545 * For each cell in \b this the number of nodes constituting cell is computed.
1546 * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1547 * So for pohyhedrons some nodes can be counted several times in the returned result.
1549 * \return a newly allocated array
1550 * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1552 DataArrayInt *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1554 checkConnectivityFullyDefined();
1555 int nbOfCells=getNumberOfCells();
1556 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1557 ret->alloc(nbOfCells,1);
1558 int *retPtr=ret->getPointer();
1559 const int *conn=getNodalConnectivity()->getConstPointer();
1560 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1561 for(int i=0;i<nbOfCells;i++,retPtr++)
1563 if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1564 *retPtr=connI[i+1]-connI[i]-1;
1566 *retPtr=connI[i+1]-connI[i]-1-std::count(conn+connI[i]+1,conn+connI[i+1],-1);
1572 * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1573 * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1575 * \return DataArrayInt * - new object to be deallocated by the caller.
1576 * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1578 DataArrayInt *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1580 checkConnectivityFullyDefined();
1581 int nbOfCells=getNumberOfCells();
1582 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1583 ret->alloc(nbOfCells,1);
1584 int *retPtr=ret->getPointer();
1585 const int *conn=getNodalConnectivity()->getConstPointer();
1586 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1587 for(int i=0;i<nbOfCells;i++,retPtr++)
1589 std::set<int> s(conn+connI[i]+1,conn+connI[i+1]);
1590 if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1591 *retPtr=(int)s.size();
1595 *retPtr=(int)s.size();
1602 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1603 * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1605 * \return a newly allocated array
1607 DataArrayInt *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1609 checkConnectivityFullyDefined();
1610 int nbOfCells=getNumberOfCells();
1611 MCAuto<DataArrayInt> ret=DataArrayInt::New();
1612 ret->alloc(nbOfCells,1);
1613 int *retPtr=ret->getPointer();
1614 const int *conn=getNodalConnectivity()->getConstPointer();
1615 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1616 for(int i=0;i<nbOfCells;i++,retPtr++,connI++)
1618 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1619 *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1625 * Removes unused nodes (the node coordinates array is shorten) and returns an array
1626 * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1627 * array mean that the corresponding old node is no more used.
1628 * \return DataArrayInt * - a new instance of DataArrayInt of length \a
1629 * this->getNumberOfNodes() before call of this method. The caller is to
1630 * delete this array using decrRef() as it is no more needed.
1631 * \throw If the coordinates array is not set.
1632 * \throw If the nodal connectivity of cells is not defined.
1633 * \throw If the nodal connectivity includes an invalid id.
1634 * \sa areAllNodesFetched
1636 * \if ENABLE_EXAMPLES
1637 * \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1638 * \ref py_mcumesh_zipCoordsTraducer "Here is a Python example".
1641 DataArrayInt *MEDCouplingUMesh::zipCoordsTraducer()
1643 return MEDCouplingPointSet::zipCoordsTraducer();
1647 * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1648 * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1650 int MEDCouplingUMesh::AreCellsEqual(const int *conn, const int *connI, int cell1, int cell2, int compType)
1655 return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1657 return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1659 return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1661 return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1663 return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1665 throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1669 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1671 int MEDCouplingUMesh::AreCellsEqualPolicy0(const int *conn, const int *connI, int cell1, int cell2)
1673 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1674 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1679 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1681 int MEDCouplingUMesh::AreCellsEqualPolicy1(const int *conn, const int *connI, int cell1, int cell2)
1683 int sz=connI[cell1+1]-connI[cell1];
1684 if(sz==connI[cell2+1]-connI[cell2])
1686 if(conn[connI[cell1]]==conn[connI[cell2]])
1688 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1689 unsigned dim=cm.getDimension();
1695 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1696 int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1697 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1698 work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1699 return work!=tmp+sz1?1:0;
1702 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1705 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1712 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1714 int MEDCouplingUMesh::AreCellsEqualPolicy2(const int *conn, const int *connI, int cell1, int cell2)
1716 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1718 if(conn[connI[cell1]]==conn[connI[cell2]])
1720 std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1721 std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1729 * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1731 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const int *conn, const int *connI, int cell1, int cell2)
1733 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1735 std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1736 std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1743 * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1745 int MEDCouplingUMesh::AreCellsEqualPolicy7(const int *conn, const int *connI, int cell1, int cell2)
1747 int sz=connI[cell1+1]-connI[cell1];
1748 if(sz==connI[cell2+1]-connI[cell2])
1750 if(conn[connI[cell1]]==conn[connI[cell2]])
1752 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1753 unsigned dim=cm.getDimension();
1759 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1760 int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1761 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1762 work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1767 std::reverse_iterator<int *> it1((int *)tmp+sz1);
1768 std::reverse_iterator<int *> it2((int *)tmp);
1769 if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1775 return work!=tmp+sz1?1:0;
1778 {//case of SEG2 and SEG3
1779 if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1781 if(!cm.isQuadratic())
1783 std::reverse_iterator<const int *> it1(conn+connI[cell1+1]);
1784 std::reverse_iterator<const int *> it2(conn+connI[cell1]+1);
1785 if(std::equal(it1,it2,conn+connI[cell2]+1))
1791 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])
1798 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1805 * This method find in candidate pool defined by 'candidates' the cells equal following the polycy 'compType'.
1806 * If any true is returned and the results will be put at the end of 'result' output parameter. If not false is returned
1807 * and result remains unchanged.
1808 * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1809 * If in 'candidates' pool -1 value is considered as an empty value.
1810 * WARNING this method returns only ONE set of result !
1812 bool MEDCouplingUMesh::AreCellsEqualInPool(const std::vector<int>& candidates, int compType, const int *conn, const int *connI, DataArrayInt *result)
1814 if(candidates.size()<1)
1817 std::vector<int>::const_iterator iter=candidates.begin();
1818 int start=(*iter++);
1819 for(;iter!=candidates.end();iter++)
1821 int status=AreCellsEqual(conn,connI,start,*iter,compType);
1826 result->pushBackSilent(start);
1830 result->pushBackSilent(*iter);
1832 result->pushBackSilent(status==2?(*iter+1):-(*iter+1));
1839 * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified
1841 * This method keeps the coordiantes of \a this. This method is time consuming.
1843 * \param [in] compType input specifying the technique used to compare cells each other.
1844 * - 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.
1845 * - 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)
1846 * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1847 * - 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
1848 * can be used for users not sensitive to orientation of cell
1849 * \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.
1850 * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1851 * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1852 * \return the correspondance array old to new in a newly allocated array.
1855 void MEDCouplingUMesh::findCommonCells(int compType, int startCellId, DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr) const
1857 MCAuto<DataArrayInt> revNodal=DataArrayInt::New(),revNodalI=DataArrayInt::New();
1858 getReverseNodalConnectivity(revNodal,revNodalI);
1859 FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1862 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, int startCellId, const DataArrayInt *nodal, const DataArrayInt *nodalI, const DataArrayInt *revNodal, const DataArrayInt *revNodalI,
1863 DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr)
1865 MCAuto<DataArrayInt> commonCells=DataArrayInt::New(),commonCellsI=DataArrayInt::New(); commonCells->alloc(0,1);
1866 int nbOfCells=nodalI->getNumberOfTuples()-1;
1867 commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1868 const int *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1869 const int *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1870 std::vector<bool> isFetched(nbOfCells,false);
1873 for(int i=0;i<nbOfCells;i++)
1877 const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1878 std::vector<int> v,v2;
1879 if(connOfNode!=connPtr+connIPtr[i+1])
1881 const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1882 v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1885 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1889 const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1890 std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1891 v2.resize(std::distance(v2.begin(),it));
1895 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1897 int pos=commonCellsI->back();
1898 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1899 for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1900 isFetched[*it]=true;
1908 for(int i=startCellId;i<nbOfCells;i++)
1912 const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1913 std::vector<int> v,v2;
1914 if(connOfNode!=connPtr+connIPtr[i+1])
1916 v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1919 for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1923 std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1924 v2.resize(std::distance(v2.begin(),it));
1928 if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1930 int pos=commonCellsI->back();
1931 commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1932 for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1933 isFetched[*it]=true;
1939 commonCellsArr=commonCells.retn();
1940 commonCellsIArr=commonCellsI.retn();
1944 * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1945 * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1946 * than \a this->getNumberOfCells() in the returned array means that there is no
1947 * corresponding cell in \a this mesh.
1948 * It is expected that \a this and \a other meshes share the same node coordinates
1949 * array, if it is not so an exception is thrown.
1950 * \param [in] other - the mesh to compare with.
1951 * \param [in] compType - specifies a cell comparison technique. For meaning of its
1952 * valid values [0,1,2], see zipConnectivityTraducer().
1953 * \param [out] arr - a new instance of DataArrayInt returning correspondence
1954 * between cells of the two meshes. It contains \a other->getNumberOfCells()
1955 * values. The caller is to delete this array using
1956 * decrRef() as it is no more needed.
1957 * \return bool - \c true if all cells of \a other mesh are present in the \a this
1960 * \if ENABLE_EXAMPLES
1961 * \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1962 * \ref py_mcumesh_areCellsIncludedIn "Here is a Python example".
1964 * \sa checkDeepEquivalOnSameNodesWith()
1965 * \sa checkGeoEquivalWith()
1967 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayInt *& arr) const
1969 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1970 int nbOfCells=getNumberOfCells();
1971 static const int possibleCompType[]={0,1,2};
1972 if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1974 std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1975 std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1977 throw INTERP_KERNEL::Exception(oss.str());
1979 MCAuto<DataArrayInt> o2n=mesh->zipConnectivityTraducer(compType,nbOfCells);
1980 arr=o2n->subArray(nbOfCells);
1981 arr->setName(other->getName());
1983 if(other->getNumberOfCells()==0)
1985 return arr->getMaxValue(tmp)<nbOfCells;
1989 * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1990 * This method tries to determine if \b other is fully included in \b this.
1991 * The main difference is that this method is not expected to throw exception.
1992 * This method has two outputs :
1994 * \param other other mesh
1995 * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1996 * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
1998 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayInt *& arr) const
2000 MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
2001 DataArrayInt *commonCells=0,*commonCellsI=0;
2002 int thisNbCells=getNumberOfCells();
2003 mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
2004 MCAuto<DataArrayInt> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
2005 const int *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
2006 int otherNbCells=other->getNumberOfCells();
2007 MCAuto<DataArrayInt> arr2=DataArrayInt::New();
2008 arr2->alloc(otherNbCells,1);
2009 arr2->fillWithZero();
2010 int *arr2Ptr=arr2->getPointer();
2011 int nbOfCommon=commonCellsI->getNumberOfTuples()-1;
2012 for(int i=0;i<nbOfCommon;i++)
2014 int start=commonCellsPtr[commonCellsIPtr[i]];
2015 if(start<thisNbCells)
2017 for(int j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
2019 int sig=commonCellsPtr[j]>0?1:-1;
2020 int val=std::abs(commonCellsPtr[j])-1;
2021 if(val>=thisNbCells)
2022 arr2Ptr[val-thisNbCells]=sig*(start+1);
2026 arr2->setName(other->getName());
2027 if(arr2->presenceOfValue(0))
2033 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
2036 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
2037 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
2039 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
2040 std::vector<const MEDCouplingUMesh *> ms(2);
2043 return MergeUMeshesOnSameCoords(ms);
2047 * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
2048 * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
2049 * cellIds is not given explicitely but by a range python like.
2054 * \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.
2055 * \return a newly allocated
2057 * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
2058 * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
2060 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(int start, int end, int step, bool keepCoords) const
2062 if(getMeshDimension()!=-1)
2063 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
2066 int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
2068 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2070 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2072 return const_cast<MEDCouplingUMesh *>(this);
2077 * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
2078 * The result mesh shares or not the node coordinates array with \a this mesh depending
2079 * on \a keepCoords parameter.
2080 * \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
2081 * to write this mesh to the MED file, its cells must be sorted using
2082 * sortCellsInMEDFileFrmt().
2083 * \param [in] begin - an array of cell ids to include to the new mesh.
2084 * \param [in] end - a pointer to last-plus-one-th element of \a begin.
2085 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2086 * array of \a this mesh, else "free" nodes are removed from the result mesh
2087 * by calling zipCoords().
2088 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2089 * to delete this mesh using decrRef() as it is no more needed.
2090 * \throw If the coordinates array is not set.
2091 * \throw If the nodal connectivity of cells is not defined.
2092 * \throw If any cell id in the array \a begin is not valid.
2094 * \if ENABLE_EXAMPLES
2095 * \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
2096 * \ref py_mcumesh_buildPartOfMySelf "Here is a Python example".
2099 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const int *begin, const int *end, bool keepCoords) const
2101 if(getMeshDimension()!=-1)
2102 return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
2106 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2108 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2110 return const_cast<MEDCouplingUMesh *>(this);
2115 * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
2117 * 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.
2118 * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
2119 * The number of cells of \b this will remain the same with this method.
2121 * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
2122 * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
2123 * \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 ).
2124 * Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
2126 void MEDCouplingUMesh::setPartOfMySelf(const int *cellIdsBg, const int *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2128 checkConnectivityFullyDefined();
2129 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2130 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2131 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2132 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2134 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2135 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2136 throw INTERP_KERNEL::Exception(oss.str());
2138 int nbOfCellsToModify=(int)std::distance(cellIdsBg,cellIdsEnd);
2139 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2141 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2142 throw INTERP_KERNEL::Exception(oss.str());
2144 int nbOfCells=getNumberOfCells();
2145 bool easyAssign=true;
2146 const int *connI=_nodal_connec_index->getConstPointer();
2147 const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2148 for(const int *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2150 if(*it>=0 && *it<nbOfCells)
2152 easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2156 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2157 throw INTERP_KERNEL::Exception(oss.str());
2162 MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2167 DataArrayInt *arrOut=0,*arrIOut=0;
2168 MEDCouplingUMesh::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2170 MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2171 setConnectivity(arrOut,arrIOut,true);
2175 void MEDCouplingUMesh::setPartOfMySelfSlice(int start, int end, int step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2177 checkConnectivityFullyDefined();
2178 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2179 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2180 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2181 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2183 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2184 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2185 throw INTERP_KERNEL::Exception(oss.str());
2187 int nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2188 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2190 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2191 throw INTERP_KERNEL::Exception(oss.str());
2193 int nbOfCells=getNumberOfCells();
2194 bool easyAssign=true;
2195 const int *connI=_nodal_connec_index->getConstPointer();
2196 const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2198 for(int i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2200 if(it>=0 && it<nbOfCells)
2202 easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2206 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2207 throw INTERP_KERNEL::Exception(oss.str());
2212 MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2217 DataArrayInt *arrOut=0,*arrIOut=0;
2218 MEDCouplingUMesh::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2220 MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2221 setConnectivity(arrOut,arrIOut,true);
2226 * Keeps from \a this only cells which constituing point id are in the ids specified by [ \a begin,\a end ).
2227 * The resulting cell ids are stored at the end of the 'cellIdsKept' parameter.
2228 * Parameter \a fullyIn specifies if a cell that has part of its nodes in ids array is kept or not.
2229 * If \a fullyIn is true only cells whose ids are \b fully contained in [ \a begin,\a end ) tab will be kept.
2231 * \param [in] begin input start of array of node ids.
2232 * \param [in] end input end of array of node ids.
2233 * \param [in] fullyIn input that specifies if all node ids must be in [ \a begin,\a end ) array to consider cell to be in.
2234 * \param [in,out] cellIdsKeptArr array where all candidate cell ids are put at the end.
2236 void MEDCouplingUMesh::fillCellIdsToKeepFromNodeIds(const int *begin, const int *end, bool fullyIn, DataArrayInt *&cellIdsKeptArr) const
2238 MCAuto<DataArrayInt> cellIdsKept=DataArrayInt::New(); cellIdsKept->alloc(0,1);
2239 checkConnectivityFullyDefined();
2241 int sz=getNodalConnectivity()->getMaxValue(tmp); sz=std::max(sz,0)+1;
2242 std::vector<bool> fastFinder(sz,false);
2243 for(const int *work=begin;work!=end;work++)
2244 if(*work>=0 && *work<sz)
2245 fastFinder[*work]=true;
2246 int nbOfCells=getNumberOfCells();
2247 const int *conn=getNodalConnectivity()->getConstPointer();
2248 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2249 for(int i=0;i<nbOfCells;i++)
2251 int ref=0,nbOfHit=0;
2252 for(const int *work2=conn+connIndex[i]+1;work2!=conn+connIndex[i+1];work2++)
2256 if(fastFinder[*work2])
2259 if((ref==nbOfHit && fullyIn) || (nbOfHit!=0 && !fullyIn))
2260 cellIdsKept->pushBackSilent(i);
2262 cellIdsKeptArr=cellIdsKept.retn();
2266 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2267 * this->getMeshDimension(), that bound some cells of \a this mesh.
2268 * The cells of lower dimension to include to the result mesh are selected basing on
2269 * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2270 * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2271 * ==\c false, a cell is copied if any its node is in the array of node ids. The
2272 * created mesh shares the node coordinates array with \a this mesh.
2273 * \param [in] begin - the array of node ids.
2274 * \param [in] end - a pointer to the (last+1)-th element of \a begin.
2275 * \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2276 * array \a begin are added, else cells whose any node is in the
2277 * array \a begin are added.
2278 * \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2279 * to delete this mesh using decrRef() as it is no more needed.
2280 * \throw If the coordinates array is not set.
2281 * \throw If the nodal connectivity of cells is not defined.
2282 * \throw If any node id in \a begin is not valid.
2284 * \if ENABLE_EXAMPLES
2285 * \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2286 * \ref py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2289 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const int *begin, const int *end, bool fullyIn) const
2291 MCAuto<DataArrayInt> desc,descIndx,revDesc,revDescIndx;
2292 desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=DataArrayInt::New(); revDescIndx=DataArrayInt::New();
2293 MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2294 desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2295 return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2299 * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2300 * this->getMeshDimension(), which bound only one cell of \a this mesh.
2301 * \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2302 * array of \a this mesh, else "free" nodes are removed from the result mesh
2303 * by calling zipCoords().
2304 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2305 * to delete this mesh using decrRef() as it is no more needed.
2306 * \throw If the coordinates array is not set.
2307 * \throw If the nodal connectivity of cells is not defined.
2309 * \if ENABLE_EXAMPLES
2310 * \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2311 * \ref py_mcumesh_buildBoundaryMesh "Here is a Python example".
2314 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2316 DataArrayInt *desc=DataArrayInt::New();
2317 DataArrayInt *descIndx=DataArrayInt::New();
2318 DataArrayInt *revDesc=DataArrayInt::New();
2319 DataArrayInt *revDescIndx=DataArrayInt::New();
2321 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2324 descIndx->decrRef();
2325 int nbOfCells=meshDM1->getNumberOfCells();
2326 const int *revDescIndxC=revDescIndx->getConstPointer();
2327 std::vector<int> boundaryCells;
2328 for(int i=0;i<nbOfCells;i++)
2329 if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2330 boundaryCells.push_back(i);
2331 revDescIndx->decrRef();
2332 MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2337 * This method returns a newly created DataArrayInt instance containing ids of cells located in boundary.
2338 * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2339 * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2341 DataArrayInt *MEDCouplingUMesh::findCellIdsOnBoundary() const
2343 checkFullyDefined();
2344 MCAuto<DataArrayInt> desc=DataArrayInt::New();
2345 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2346 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2347 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2349 buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2350 desc=(DataArrayInt*)0; descIndx=(DataArrayInt*)0;
2352 MCAuto<DataArrayInt> tmp=revDescIndx->deltaShiftIndex();
2353 MCAuto<DataArrayInt> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayInt*)0;
2354 const int *revDescPtr=revDesc->getConstPointer();
2355 const int *revDescIndxPtr=revDescIndx->getConstPointer();
2356 int nbOfCells=getNumberOfCells();
2357 std::vector<bool> ret1(nbOfCells,false);
2359 for(const int *pt=faceIds->begin();pt!=faceIds->end();pt++)
2360 if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2361 { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2363 DataArrayInt *ret2=DataArrayInt::New();
2365 int *ret2Ptr=ret2->getPointer();
2367 for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2370 ret2->setName("BoundaryCells");
2375 * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2376 * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2377 * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2378 * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2380 * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2381 * 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
2382 * equals a cell in \b otherDimM1OnSameCoords.
2384 * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2385 * are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2387 * \param [in] otherDimM1OnSameCoords
2388 * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2389 * \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
2390 * cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2392 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *&cellIdsRk0, DataArrayInt *&cellIdsRk1) const
2394 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2395 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2396 checkConnectivityFullyDefined();
2397 otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2398 if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2399 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2400 MCAuto<DataArrayInt> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2401 MCAuto<DataArrayInt> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2402 MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2403 MCAuto<DataArrayInt> descThisPart=DataArrayInt::New(),descIThisPart=DataArrayInt::New(),revDescThisPart=DataArrayInt::New(),revDescIThisPart=DataArrayInt::New();
2404 MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2405 const int *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2406 DataArrayInt *idsOtherInConsti=0;
2407 bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2408 MCAuto<DataArrayInt> idsOtherInConstiAuto(idsOtherInConsti);
2410 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2412 for(const int *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2413 s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2414 MCAuto<DataArrayInt> s1arr_renum1=DataArrayInt::New(); s1arr_renum1->alloc((int)s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2415 s1arr_renum1->sort();
2416 cellIdsRk0=s0arr.retn();
2417 //cellIdsRk1=s_renum1.retn();
2418 cellIdsRk1=s1arr_renum1.retn();
2422 * 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
2423 * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2425 * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2427 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2429 MCAuto<DataArrayInt> desc=DataArrayInt::New();
2430 MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2431 MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2432 MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2434 MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2435 revDesc=0; desc=0; descIndx=0;
2436 MCAuto<DataArrayInt> revDescIndx2=revDescIndx->deltaShiftIndex();
2437 MCAuto<DataArrayInt> part=revDescIndx2->findIdsEqual(1);
2438 return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2442 * Finds nodes lying on the boundary of \a this mesh.
2443 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of found
2444 * nodes. The caller is to delete this array using decrRef() as it is no
2446 * \throw If the coordinates array is not set.
2447 * \throw If the nodal connectivity of cells is node defined.
2449 * \if ENABLE_EXAMPLES
2450 * \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2451 * \ref py_mcumesh_findBoundaryNodes "Here is a Python example".
2454 DataArrayInt *MEDCouplingUMesh::findBoundaryNodes() const
2456 MCAuto<MEDCouplingUMesh> skin=computeSkin();
2457 return skin->computeFetchedNodeIds();
2460 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2463 return const_cast<MEDCouplingUMesh *>(this);
2467 * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2468 * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2469 * 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.
2470 * 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.
2471 * 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.
2473 * \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
2474 * parameter is altered during the call.
2475 * \param [out] nodeIdsToDuplicate node ids needed to be duplicated following the algorithm explain above.
2476 * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2477 * \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.
2479 * \warning This method modifies param \b otherDimM1OnSameCoords (for speed reasons).
2481 void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *& nodeIdsToDuplicate,
2482 DataArrayInt *& cellIdsNeededToBeRenum, DataArrayInt *& cellIdsNotModified) const
2484 typedef MCAuto<DataArrayInt> DAInt;
2485 typedef MCAuto<MEDCouplingUMesh> MCUMesh;
2487 checkFullyDefined();
2488 otherDimM1OnSameCoords.checkFullyDefined();
2489 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2490 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2491 if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2492 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2494 // Checking star-shaped M1 group:
2495 DAInt dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2496 MCUMesh meshM2 = otherDimM1OnSameCoords.buildDescendingConnectivity(dt0, dit0, rdt0, rdit0);
2497 DAInt dsi = rdit0->deltaShiftIndex();
2498 DAInt idsTmp0 = dsi->findIdsNotInRange(-1, 3);
2499 if(idsTmp0->getNumberOfTuples())
2500 throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2501 dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2503 // Get extreme nodes from the group (they won't be duplicated), ie nodes belonging to boundary cells of M1
2504 DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2505 MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2506 DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2507 // Remove from the list points on the boundary of the M0 mesh (those need duplication!)
2508 dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2509 MCUMesh m0desc = buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0;
2510 dsi = rdit0->deltaShiftIndex();
2511 DAInt boundSegs = dsi->findIdsEqual(1); // boundary segs/faces of the M0 mesh
2512 MCUMesh m0descSkin = static_cast<MEDCouplingUMesh *>(m0desc->buildPartOfMySelf(boundSegs->begin(),boundSegs->end(), true));
2513 DAInt fNodes = m0descSkin->computeFetchedNodeIds();
2514 // In 3D, some points on the boundary of M0 still need duplication:
2516 if (getMeshDimension() == 3)
2518 DAInt dnu1=DataArrayInt::New(), dnu2=DataArrayInt::New(), dnu3=DataArrayInt::New(), dnu4=DataArrayInt::New();
2519 MCUMesh m0descSkinDesc = m0descSkin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4);
2520 dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2521 DataArrayInt * corresp=0;
2522 meshM2->areCellsIncludedIn(m0descSkinDesc,2,corresp);
2523 DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2525 if (validIds->getNumberOfTuples())
2527 MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0descSkinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2528 DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2529 DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2530 notDup = xtrem->buildSubstraction(fNodes1);
2533 notDup = xtrem->buildSubstraction(fNodes);
2536 notDup = xtrem->buildSubstraction(fNodes);
2538 // Now compute cells around group (i.e. cells where we will do the propagation to identify the two sub-sets delimited by the group)
2539 DAInt m1Nodes = otherDimM1OnSameCoords.computeFetchedNodeIds();
2540 DAInt dupl = m1Nodes->buildSubstraction(notDup);
2541 DAInt cellsAroundGroup = getCellIdsLyingOnNodes(dupl->begin(), dupl->end(), false); // false= take cell in, even if not all nodes are in notDup
2544 MCUMesh m0Part2=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroup->begin(),cellsAroundGroup->end(),true));
2545 int nCells2 = m0Part2->getNumberOfCells();
2546 DAInt desc00=DataArrayInt::New(),descI00=DataArrayInt::New(),revDesc00=DataArrayInt::New(),revDescI00=DataArrayInt::New();
2547 MCUMesh m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00);
2549 // Neighbor information of the mesh without considering the crack (serves to count how many connex pieces it is made of)
2550 DataArrayInt *tmp00=0,*tmp11=0;
2551 MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00, tmp00, tmp11);
2552 DAInt neighInit00(tmp00);
2553 DAInt neighIInit00(tmp11);
2554 // Neighbor information of the mesh WITH the crack (some neighbors are removed):
2555 DataArrayInt *idsTmp=0;
2556 bool b=m01->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsTmp);
2558 // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2559 // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2560 MEDCouplingUMesh::RemoveIdsFromIndexedArrays(ids->begin(),ids->end(),desc00,descI00);
2561 DataArrayInt *tmp0=0,*tmp1=0;
2562 // Compute the neighbor of each cell in m0Part2, taking into account the broken link above. Two
2563 // cells on either side of the crack (defined by the mesh of low dimension) are not neighbor anymore.
2564 ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00,tmp0,tmp1);
2565 DAInt neigh00(tmp0);
2566 DAInt neighI00(tmp1);
2568 // For each initial connex part of the sub-mesh (or said differently for each independent crack):
2569 int seed = 0, nIter = 0;
2570 int nIterMax = nCells2+1; // Safety net for the loop
2571 DAInt hitCells = DataArrayInt::New(); hitCells->alloc(nCells2);
2572 hitCells->fillWithValue(-1);
2573 DAInt cellsToModifyConn0_torenum = DataArrayInt::New();
2574 cellsToModifyConn0_torenum->alloc(0,1);
2575 while (nIter < nIterMax)
2577 DAInt t = hitCells->findIdsEqual(-1);
2578 if (!t->getNumberOfTuples())
2580 // Connex zone without the crack (to compute the next seed really)
2582 DAInt connexCheck = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neighInit00,neighIInit00, -1, dnu);
2584 for (int * ptr = connexCheck->getPointer(); cnt < connexCheck->getNumberOfTuples(); ptr++, cnt++)
2585 hitCells->setIJ(*ptr,0,1);
2586 // Connex zone WITH the crack (to identify cells lying on either part of the crack)
2587 DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neigh00,neighI00, -1, dnu);
2588 cellsToModifyConn0_torenum = DataArrayInt::Aggregate(cellsToModifyConn0_torenum, spreadZone, 0);
2589 // Compute next seed, i.e. a cell in another connex part, which was not covered by the previous iterations
2590 DAInt comple = cellsToModifyConn0_torenum->buildComplement(nCells2);
2591 DAInt nonHitCells = hitCells->findIdsEqual(-1);
2592 DAInt intersec = nonHitCells->buildIntersection(comple);
2593 if (intersec->getNumberOfTuples())
2594 { seed = intersec->getIJ(0,0); }
2599 if (nIter >= nIterMax)
2600 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate(): internal error - too many iterations.");
2602 DAInt cellsToModifyConn1_torenum=cellsToModifyConn0_torenum->buildComplement(neighI00->getNumberOfTuples()-1);
2603 cellsToModifyConn0_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2604 cellsToModifyConn1_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2606 cellIdsNeededToBeRenum=cellsToModifyConn0_torenum.retn();
2607 cellIdsNotModified=cellsToModifyConn1_torenum.retn();
2608 nodeIdsToDuplicate=dupl.retn();
2612 * This method operates a modification of the connectivity and coords in \b this.
2613 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2614 * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2615 * 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
2616 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2617 * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2619 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2621 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2622 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2624 void MEDCouplingUMesh::duplicateNodes(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd)
2626 int nbOfNodes=getNumberOfNodes();
2627 duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2628 duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2632 * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2633 * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2635 * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2637 * \sa renumberNodesInConn
2639 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(int offset)
2641 checkConnectivityFullyDefined();
2642 int *conn(getNodalConnectivity()->getPointer());
2643 const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2644 int nbOfCells(getNumberOfCells());
2645 for(int i=0;i<nbOfCells;i++)
2646 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2648 int& node=conn[iconn];
2649 if(node>=0)//avoid polyhedron separator
2654 _nodal_connec->declareAsNew();
2659 * Same than renumberNodesInConn(const int *) except that here the format of old-to-new traducer is using map instead
2660 * 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
2663 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<int,int>& newNodeNumbersO2N)
2665 checkConnectivityFullyDefined();
2666 int *conn(getNodalConnectivity()->getPointer());
2667 const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2668 int nbOfCells(getNumberOfCells());
2669 for(int i=0;i<nbOfCells;i++)
2670 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2672 int& node=conn[iconn];
2673 if(node>=0)//avoid polyhedron separator
2675 INTERP_KERNEL::HashMap<int,int>::const_iterator it(newNodeNumbersO2N.find(node));
2676 if(it!=newNodeNumbersO2N.end())
2682 std::ostringstream oss; oss << "MEDCouplingUMesh::renumberNodesInConn(map) : presence in connectivity for cell #" << i << " of node #" << node << " : Not in map !";
2683 throw INTERP_KERNEL::Exception(oss.str());
2687 _nodal_connec->declareAsNew();
2692 * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2693 * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2694 * This method is a generalization of shiftNodeNumbersInConn().
2695 * \warning This method performs no check of validity of new ids. **Use it with care !**
2696 * \param [in] newNodeNumbersO2N - a permutation array, of length \a
2697 * this->getNumberOfNodes(), in "Old to New" mode.
2698 * See \ref numbering for more info on renumbering modes.
2699 * \throw If the nodal connectivity of cells is not defined.
2701 * \if ENABLE_EXAMPLES
2702 * \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2703 * \ref py_mcumesh_renumberNodesInConn "Here is a Python example".
2706 void MEDCouplingUMesh::renumberNodesInConn(const int *newNodeNumbersO2N)
2708 checkConnectivityFullyDefined();
2709 int *conn=getNodalConnectivity()->getPointer();
2710 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2711 int nbOfCells(getNumberOfCells());
2712 for(int i=0;i<nbOfCells;i++)
2713 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2715 int& node=conn[iconn];
2716 if(node>=0)//avoid polyhedron separator
2718 node=newNodeNumbersO2N[node];
2721 _nodal_connec->declareAsNew();
2726 * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2727 * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2728 * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2730 * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2732 void MEDCouplingUMesh::shiftNodeNumbersInConn(int delta)
2734 checkConnectivityFullyDefined();
2735 int *conn=getNodalConnectivity()->getPointer();
2736 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2737 int nbOfCells=getNumberOfCells();
2738 for(int i=0;i<nbOfCells;i++)
2739 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2741 int& node=conn[iconn];
2742 if(node>=0)//avoid polyhedron separator
2747 _nodal_connec->declareAsNew();
2752 * This method operates a modification of the connectivity in \b this.
2753 * 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.
2754 * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2755 * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2756 * 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
2757 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2758 * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2760 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2761 * As an another consequense after the call of this method \b this can be transiently non cohrent.
2763 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2764 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2765 * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ).
2767 void MEDCouplingUMesh::duplicateNodesInConn(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd, int offset)
2769 checkConnectivityFullyDefined();
2770 std::map<int,int> m;
2772 for(const int *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2774 int *conn=getNodalConnectivity()->getPointer();
2775 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2776 int nbOfCells=getNumberOfCells();
2777 for(int i=0;i<nbOfCells;i++)
2778 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2780 int& node=conn[iconn];
2781 if(node>=0)//avoid polyhedron separator
2783 std::map<int,int>::iterator it=m.find(node);
2792 * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2794 * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2795 * After the call of this method the number of cells remains the same as before.
2797 * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2798 * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2799 * be strictly in [0;this->getNumberOfCells()).
2801 * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2802 * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2803 * should be contained in[0;this->getNumberOfCells()).
2805 * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2808 void MEDCouplingUMesh::renumberCells(const int *old2NewBg, bool check)
2810 checkConnectivityFullyDefined();
2811 int nbCells=getNumberOfCells();
2812 const int *array=old2NewBg;
2814 array=DataArrayInt::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2816 const int *conn=_nodal_connec->getConstPointer();
2817 const int *connI=_nodal_connec_index->getConstPointer();
2818 MCAuto<DataArrayInt> o2n=DataArrayInt::New(); o2n->useArray(array,false,C_DEALLOC,nbCells,1);
2819 MCAuto<DataArrayInt> n2o=o2n->invertArrayO2N2N2O(nbCells);
2820 const int *n2oPtr=n2o->begin();
2821 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
2822 newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2823 newConn->copyStringInfoFrom(*_nodal_connec);
2824 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
2825 newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2826 newConnI->copyStringInfoFrom(*_nodal_connec_index);
2828 int *newC=newConn->getPointer();
2829 int *newCI=newConnI->getPointer();
2832 for(int i=0;i<nbCells;i++)
2835 int nbOfElts=connI[pos+1]-connI[pos];
2836 newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2841 setConnectivity(newConn,newConnI);
2843 free(const_cast<int *>(array));
2847 * Finds cells whose bounding boxes intersect a given bounding box.
2848 * \param [in] bbox - an array defining the bounding box via coordinates of its
2849 * extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2851 * \param [in] eps - a factor used to increase size of the bounding box of cell
2852 * before comparing it with \a bbox. This factor is multiplied by the maximal
2853 * extent of the bounding box of cell to produce an addition to this bounding box.
2854 * \return DataArrayInt * - a new instance of DataArrayInt holding ids for found
2855 * cells. The caller is to delete this array using decrRef() as it is no more
2857 * \throw If the coordinates array is not set.
2858 * \throw If the nodal connectivity of cells is not defined.
2860 * \if ENABLE_EXAMPLES
2861 * \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2862 * \ref py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2865 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2867 MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2868 if(getMeshDimension()==-1)
2870 elems->pushBackSilent(0);
2871 return elems.retn();
2873 int dim=getSpaceDimension();
2874 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2875 const int* conn = getNodalConnectivity()->getConstPointer();
2876 const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2877 const double* coords = getCoords()->getConstPointer();
2878 int nbOfCells=getNumberOfCells();
2879 for ( int ielem=0; ielem<nbOfCells;ielem++ )
2881 for (int i=0; i<dim; i++)
2883 elem_bb[i*2]=std::numeric_limits<double>::max();
2884 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2887 for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2889 int node= conn[inode];
2890 if(node>=0)//avoid polyhedron separator
2892 for (int idim=0; idim<dim; idim++)
2894 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2896 elem_bb[idim*2] = coords[node*dim+idim] ;
2898 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2900 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2905 if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2906 elems->pushBackSilent(ielem);
2908 return elems.retn();
2912 * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2913 * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2914 * added in 'elems' parameter.
2916 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2918 MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2919 if(getMeshDimension()==-1)
2921 elems->pushBackSilent(0);
2922 return elems.retn();
2924 int dim=getSpaceDimension();
2925 INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2926 const int* conn = getNodalConnectivity()->getConstPointer();
2927 const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2928 const double* coords = getCoords()->getConstPointer();
2929 int nbOfCells=getNumberOfCells();
2930 for ( int ielem=0; ielem<nbOfCells;ielem++ )
2932 for (int i=0; i<dim; i++)
2934 elem_bb[i*2]=std::numeric_limits<double>::max();
2935 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2938 for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2940 int node= conn[inode];
2941 if(node>=0)//avoid polyhedron separator
2943 for (int idim=0; idim<dim; idim++)
2945 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2947 elem_bb[idim*2] = coords[node*dim+idim] ;
2949 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2951 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2956 if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
2957 elems->pushBackSilent(ielem);
2959 return elems.retn();
2963 * Returns a type of a cell by its id.
2964 * \param [in] cellId - the id of the cell of interest.
2965 * \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
2966 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2968 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(int cellId) const
2970 const int *ptI=_nodal_connec_index->getConstPointer();
2971 const int *pt=_nodal_connec->getConstPointer();
2972 if(cellId>=0 && cellId<(int)_nodal_connec_index->getNbOfElems()-1)
2973 return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2976 std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2977 throw INTERP_KERNEL::Exception(oss.str());
2982 * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2983 * This method does not throw exception if geometric type \a type is not in \a this.
2984 * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2985 * The coordinates array is not considered here.
2987 * \param [in] type the geometric type
2988 * \return cell ids in this having geometric type \a type.
2990 DataArrayInt *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2993 MCAuto<DataArrayInt> ret=DataArrayInt::New();
2995 checkConnectivityFullyDefined();
2996 int nbCells=getNumberOfCells();
2997 int mdim=getMeshDimension();
2998 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
2999 if(mdim!=(int)cm.getDimension())
3000 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
3001 const int *ptI=_nodal_connec_index->getConstPointer();
3002 const int *pt=_nodal_connec->getConstPointer();
3003 for(int i=0;i<nbCells;i++)
3005 if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
3006 ret->pushBackSilent(i);
3012 * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
3014 int MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
3016 const int *ptI=_nodal_connec_index->getConstPointer();
3017 const int *pt=_nodal_connec->getConstPointer();
3018 int nbOfCells=getNumberOfCells();
3020 for(int i=0;i<nbOfCells;i++)
3021 if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
3027 * Returns the nodal connectivity of a given cell.
3028 * The separator of faces within polyhedron connectivity (-1) is not returned, thus
3029 * all returned node ids can be used in getCoordinatesOfNode().
3030 * \param [in] cellId - an id of the cell of interest.
3031 * \param [in,out] conn - a vector where the node ids are appended. It is not
3032 * cleared before the appending.
3033 * \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
3035 void MEDCouplingUMesh::getNodeIdsOfCell(int cellId, std::vector<int>& conn) const
3037 const int *ptI=_nodal_connec_index->getConstPointer();
3038 const int *pt=_nodal_connec->getConstPointer();
3039 for(const int *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
3044 std::string MEDCouplingUMesh::simpleRepr() const
3046 static const char msg0[]="No coordinates specified !";
3047 std::ostringstream ret;
3048 ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
3049 ret << "Description of mesh : \"" << getDescription() << "\"\n";
3051 double tt=getTime(tmpp1,tmpp2);
3052 ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
3053 ret << "Iteration : " << tmpp1 << " Order : " << tmpp2 << "\n";
3055 { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
3057 { ret << " Mesh dimension has not been set or is invalid !"; }
3060 const int spaceDim=getSpaceDimension();
3061 ret << spaceDim << "\nInfo attached on space dimension : ";
3062 for(int i=0;i<spaceDim;i++)
3063 ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
3067 ret << msg0 << "\n";
3068 ret << "Number of nodes : ";
3070 ret << getNumberOfNodes() << "\n";
3072 ret << msg0 << "\n";
3073 ret << "Number of cells : ";
3074 if(_nodal_connec!=0 && _nodal_connec_index!=0)
3075 ret << getNumberOfCells() << "\n";
3077 ret << "No connectivity specified !" << "\n";
3078 ret << "Cell types present : ";
3079 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
3081 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
3082 ret << cm.getRepr() << " ";
3088 std::string MEDCouplingUMesh::advancedRepr() const
3090 std::ostringstream ret;
3091 ret << simpleRepr();
3092 ret << "\nCoordinates array : \n___________________\n\n";
3094 _coords->reprWithoutNameStream(ret);
3096 ret << "No array set !\n";
3097 ret << "\n\nConnectivity arrays : \n_____________________\n\n";
3098 reprConnectivityOfThisLL(ret);
3103 * This method returns a C++ code that is a dump of \a this.
3104 * This method will throw if this is not fully defined.
3106 std::string MEDCouplingUMesh::cppRepr() const
3108 static const char coordsName[]="coords";
3109 static const char connName[]="conn";
3110 static const char connIName[]="connI";
3111 checkFullyDefined();
3112 std::ostringstream ret; ret << "// coordinates" << std::endl;
3113 _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
3114 _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
3115 _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
3116 ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
3117 ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
3118 ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
3119 ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
3123 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
3125 std::ostringstream ret;
3126 reprConnectivityOfThisLL(ret);
3131 * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsability to deal with.
3132 * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
3133 * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
3136 * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
3137 * 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
3138 * with number of tuples set to 0, if not the array is taken as this in the returned instance.
3140 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(int spaceDim) const
3142 int mdim=getMeshDimension();
3144 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
3145 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
3146 MCAuto<DataArrayInt> tmp1,tmp2;
3147 bool needToCpyCT=true;
3150 tmp1=DataArrayInt::New(); tmp1->alloc(0,1);
3158 if(!_nodal_connec_index)
3160 tmp2=DataArrayInt::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
3165 tmp2=_nodal_connec_index;
3168 ret->setConnectivity(tmp1,tmp2,false);
3173 MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
3174 ret->setCoords(coords);
3177 ret->setCoords(_coords);
3181 void MEDCouplingUMesh::reprConnectivityOfThisLL(std::ostringstream& stream) const
3183 if(_nodal_connec!=0 && _nodal_connec_index!=0)
3185 int nbOfCells=getNumberOfCells();
3186 const int *c=_nodal_connec->getConstPointer();
3187 const int *ci=_nodal_connec_index->getConstPointer();
3188 for(int i=0;i<nbOfCells;i++)
3190 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[i]]);
3191 stream << "Cell #" << i << " " << cm.getRepr() << " : ";
3192 std::copy(c+ci[i]+1,c+ci[i+1],std::ostream_iterator<int>(stream," "));
3197 stream << "Connectivity not defined !\n";
3200 int MEDCouplingUMesh::getNumberOfNodesInCell(int cellId) const
3202 const int *ptI=_nodal_connec_index->getConstPointer();
3203 const int *pt=_nodal_connec->getConstPointer();
3204 if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
3205 return ptI[cellId+1]-ptI[cellId]-1;
3207 return (int)std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind2nd(std::not_equal_to<int>(),-1));
3211 * Returns types of cells of the specified part of \a this mesh.
3212 * This method avoids computing sub-mesh explicitely to get its types.
3213 * \param [in] begin - an array of cell ids of interest.
3214 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3215 * \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3216 * describing the cell types.
3217 * \throw If the coordinates array is not set.
3218 * \throw If the nodal connectivity of cells is not defined.
3219 * \sa getAllGeoTypes()
3221 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const int *begin, const int *end) const
3223 checkFullyDefined();
3224 std::set<INTERP_KERNEL::NormalizedCellType> ret;
3225 const int *conn=_nodal_connec->getConstPointer();
3226 const int *connIndex=_nodal_connec_index->getConstPointer();
3227 for(const int *w=begin;w!=end;w++)
3228 ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3233 * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3234 * Optionally updates
3235 * a set of types of cells constituting \a this mesh.
3236 * This method is for advanced users having prepared their connectivity before. For
3237 * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3238 * \param [in] conn - the nodal connectivity array.
3239 * \param [in] connIndex - the nodal connectivity index array.
3240 * \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3243 void MEDCouplingUMesh::setConnectivity(DataArrayInt *conn, DataArrayInt *connIndex, bool isComputingTypes)
3245 DataArrayInt::SetArrayIn(conn,_nodal_connec);
3246 DataArrayInt::SetArrayIn(connIndex,_nodal_connec_index);
3247 if(isComputingTypes)
3253 * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3254 * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3256 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCopy):MEDCouplingPointSet(other,deepCopy),_mesh_dim(other._mesh_dim),
3257 _nodal_connec(0),_nodal_connec_index(0),
3258 _types(other._types)
3260 if(other._nodal_connec)
3261 _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCopy);
3262 if(other._nodal_connec_index)
3263 _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCopy);
3266 MEDCouplingUMesh::~MEDCouplingUMesh()
3269 _nodal_connec->decrRef();
3270 if(_nodal_connec_index)
3271 _nodal_connec_index->decrRef();
3275 * Recomputes a set of cell types of \a this mesh. For more info see
3276 * \ref MEDCouplingUMeshNodalConnectivity.
3278 void MEDCouplingUMesh::computeTypes()
3280 ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3284 * This method checks that all arrays are set. If yes nothing done if no an exception is thrown.
3286 void MEDCouplingUMesh::checkFullyDefined() const
3288 if(!_nodal_connec_index || !_nodal_connec || !_coords)
3289 throw INTERP_KERNEL::Exception("Reverse nodal connectivity computation requires full connectivity and coordinates set in unstructured mesh.");
3293 * This method checks that all connectivity arrays are set. If yes nothing done if no an exception is thrown.
3295 void MEDCouplingUMesh::checkConnectivityFullyDefined() const
3297 if(!_nodal_connec_index || !_nodal_connec)
3298 throw INTERP_KERNEL::Exception("Reverse nodal connectivity computation requires full connectivity set in unstructured mesh.");
3302 * Returns a number of cells constituting \a this mesh.
3303 * \return int - the number of cells in \a this mesh.
3304 * \throw If the nodal connectivity of cells is not defined.
3306 int MEDCouplingUMesh::getNumberOfCells() const
3308 if(_nodal_connec_index)
3309 return _nodal_connec_index->getNumberOfTuples()-1;
3314 throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3318 * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3319 * mesh. For more info see \ref meshes.
3320 * \return int - the dimension of \a this mesh.
3321 * \throw If the mesh dimension is not defined using setMeshDimension().
3323 int MEDCouplingUMesh::getMeshDimension() const
3326 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3331 * Returns a length of the nodal connectivity array.
3332 * This method is for test reason. Normally the integer returned is not useable by
3333 * user. For more info see \ref MEDCouplingUMeshNodalConnectivity.
3334 * \return int - the length of the nodal connectivity array.
3336 int MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3338 return _nodal_connec->getNbOfElems();
3342 * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3344 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<int>& tinyInfo, std::vector<std::string>& littleStrings) const
3346 MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3347 tinyInfo.push_back(getMeshDimension());
3348 tinyInfo.push_back(getNumberOfCells());
3350 tinyInfo.push_back(getNodalConnectivityArrayLen());
3352 tinyInfo.push_back(-1);
3356 * First step of unserialization process.
3358 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<int>& tinyInfo) const
3360 return tinyInfo[6]<=0;
3364 * Second step of serialization process.
3365 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3368 * \param littleStrings
3370 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<int>& tinyInfo, DataArrayInt *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3372 MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3374 a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3378 * Third and final step of serialization process.
3380 void MEDCouplingUMesh::serialize(DataArrayInt *&a1, DataArrayDouble *&a2) const
3382 MEDCouplingPointSet::serialize(a1,a2);
3383 if(getMeshDimension()>-1)
3385 a1=DataArrayInt::New();
3386 a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3387 int *ptA1=a1->getPointer();
3388 const int *conn=getNodalConnectivity()->getConstPointer();
3389 const int *index=getNodalConnectivityIndex()->getConstPointer();
3390 ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3391 std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3398 * Second and final unserialization process.
3399 * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3401 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<int>& tinyInfo, const DataArrayInt *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3403 MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3404 setMeshDimension(tinyInfo[5]);
3408 const int *recvBuffer=a1->getConstPointer();
3409 MCAuto<DataArrayInt> myConnecIndex=DataArrayInt::New();
3410 myConnecIndex->alloc(tinyInfo[6]+1,1);
3411 std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3412 MCAuto<DataArrayInt> myConnec=DataArrayInt::New();
3413 myConnec->alloc(tinyInfo[7],1);
3414 std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3415 setConnectivity(myConnec, myConnecIndex);
3420 * This is the low algorithm of MEDCouplingUMesh::buildPartOfMySelfSlice.
3421 * CellIds are given using range specified by a start an end and step.
3423 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice(int start, int end, int step) const
3425 checkFullyDefined();
3426 int ncell=getNumberOfCells();
3427 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New();
3428 ret->_mesh_dim=_mesh_dim;
3429 ret->setCoords(_coords);
3430 int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice : ");
3431 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(newNbOfCells+1,1);
3432 int *newConnIPtr=newConnI->getPointer(); *newConnIPtr=0;
3434 const int *conn=_nodal_connec->getConstPointer();
3435 const int *connIndex=_nodal_connec_index->getConstPointer();
3436 for(int i=0;i<newNbOfCells;i++,newConnIPtr++,work+=step)
3438 if(work>=0 && work<ncell)
3440 newConnIPtr[1]=newConnIPtr[0]+connIndex[work+1]-connIndex[work];
3444 std::ostringstream oss; oss << "MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice : On pos #" << i << " input cell id =" << work << " should be in [0," << ncell << ") !";
3445 throw INTERP_KERNEL::Exception(oss.str());
3448 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(newConnIPtr[0],1);
3449 int *newConnPtr=newConn->getPointer();
3450 std::set<INTERP_KERNEL::NormalizedCellType> types;
3452 for(int i=0;i<newNbOfCells;i++,newConnIPtr++,work+=step)
3454 types.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[work]]);
3455 newConnPtr=std::copy(conn+connIndex[work],conn+connIndex[work+1],newConnPtr);
3457 ret->setConnectivity(newConn,newConnI,false);
3459 ret->copyTinyInfoFrom(this);
3464 * This is the low algorithm of MEDCouplingUMesh::buildPartOfMySelf.
3465 * Keeps from \a this only cells which constituing point id are in the ids specified by [ \a begin,\a end ).
3466 * The return newly allocated mesh will share the same coordinates as \a this.
3468 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfKeepCoords(const int *begin, const int *end) const
3470 checkConnectivityFullyDefined();
3471 int ncell=getNumberOfCells();
3472 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New();
3473 ret->_mesh_dim=_mesh_dim;
3474 ret->setCoords(_coords);
3475 std::size_t nbOfElemsRet=std::distance(begin,end);
3476 int *connIndexRet=(int *)malloc((nbOfElemsRet+1)*sizeof(int));
3478 const int *conn=_nodal_connec->getConstPointer();
3479 const int *connIndex=_nodal_connec_index->getConstPointer();
3481 for(const int *work=begin;work!=end;work++,newNbring++)
3483 if(*work>=0 && *work<ncell)
3484 connIndexRet[newNbring+1]=connIndexRet[newNbring]+connIndex[*work+1]-connIndex[*work];
3488 std::ostringstream oss; oss << "MEDCouplingUMesh::buildPartOfMySelfKeepCoords : On pos #" << std::distance(begin,work) << " input cell id =" << *work << " should be in [0," << ncell << ") !";
3489 throw INTERP_KERNEL::Exception(oss.str());
3492 int *connRet=(int *)malloc(connIndexRet[nbOfElemsRet]*sizeof(int));
3493 int *connRetWork=connRet;
3494 std::set<INTERP_KERNEL::NormalizedCellType> types;
3495 for(const int *work=begin;work!=end;work++)
3497 types.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*work]]);
3498 connRetWork=std::copy(conn+connIndex[*work],conn+connIndex[*work+1],connRetWork);
3500 MCAuto<DataArrayInt> connRetArr=DataArrayInt::New();
3501 connRetArr->useArray(connRet,true,C_DEALLOC,connIndexRet[nbOfElemsRet],1);
3502 MCAuto<DataArrayInt> connIndexRetArr=DataArrayInt::New();
3503 connIndexRetArr->useArray(connIndexRet,true,C_DEALLOC,(int)nbOfElemsRet+1,1);
3504 ret->setConnectivity(connRetArr,connIndexRetArr,false);
3506 ret->copyTinyInfoFrom(this);
3511 * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3513 * For 1D cells, the returned field contains lengths.<br>
3514 * For 2D cells, the returned field contains areas.<br>
3515 * For 3D cells, the returned field contains volumes.
3516 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3517 * orientation, i.e. the volume is always positive.
3518 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3519 * and one time . The caller is to delete this field using decrRef() as it is no
3522 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3524 std::string name="MeasureOfMesh_";
3526 int nbelem=getNumberOfCells();
3527 MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3528 field->setName(name);
3529 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3530 array->alloc(nbelem,1);
3531 double *area_vol=array->getPointer();
3532 field->setArray(array) ; array=0;
3533 field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3534 field->synchronizeTimeWithMesh();
3535 if(getMeshDimension()!=-1)
3538 INTERP_KERNEL::NormalizedCellType type;
3539 int dim_space=getSpaceDimension();
3540 const double *coords=getCoords()->getConstPointer();
3541 const int *connec=getNodalConnectivity()->getConstPointer();
3542 const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3543 for(int iel=0;iel<nbelem;iel++)
3545 ipt=connec_index[iel];
3546 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3547 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);
3550 std::transform(area_vol,area_vol+nbelem,area_vol,std::ptr_fun<double,double>(fabs));
3554 area_vol[0]=std::numeric_limits<double>::max();
3556 return field.retn();
3560 * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3562 * For 1D cells, the returned array contains lengths.<br>
3563 * For 2D cells, the returned array contains areas.<br>
3564 * For 3D cells, the returned array contains volumes.
3565 * This method avoids building explicitly a part of \a this mesh to perform the work.
3566 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3567 * orientation, i.e. the volume is always positive.
3568 * \param [in] begin - an array of cell ids of interest.
3569 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3570 * \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3571 * delete this array using decrRef() as it is no more needed.
3573 * \if ENABLE_EXAMPLES
3574 * \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3575 * \ref py_mcumesh_getPartMeasureField "Here is a Python example".
3577 * \sa getMeasureField()
3579 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const int *begin, const int *end) const
3581 std::string name="PartMeasureOfMesh_";
3583 int nbelem=(int)std::distance(begin,end);
3584 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3585 array->setName(name);
3586 array->alloc(nbelem,1);
3587 double *area_vol=array->getPointer();
3588 if(getMeshDimension()!=-1)
3591 INTERP_KERNEL::NormalizedCellType type;
3592 int dim_space=getSpaceDimension();
3593 const double *coords=getCoords()->getConstPointer();
3594 const int *connec=getNodalConnectivity()->getConstPointer();
3595 const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3596 for(const int *iel=begin;iel!=end;iel++)
3598 ipt=connec_index[*iel];
3599 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3600 *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<int,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3603 std::transform(array->getPointer(),area_vol,array->getPointer(),std::ptr_fun<double,double>(fabs));
3607 area_vol[0]=std::numeric_limits<double>::max();
3609 return array.retn();
3613 * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3614 * \a this one. The returned field contains the dual cell volume for each corresponding
3615 * node in \a this mesh. In other words, the field returns the getMeasureField() of
3616 * the dual mesh in P1 sens of \a this.<br>
3617 * For 1D cells, the returned field contains lengths.<br>
3618 * For 2D cells, the returned field contains areas.<br>
3619 * For 3D cells, the returned field contains volumes.
3620 * This method is useful to check "P1*" conservative interpolators.
3621 * \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3622 * orientation, i.e. the volume is always positive.
3623 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3624 * nodes and one time. The caller is to delete this array using decrRef() as
3625 * it is no more needed.
3627 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3629 MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3630 std::string name="MeasureOnNodeOfMesh_";
3632 int nbNodes=getNumberOfNodes();
3633 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3634 double cst=1./((double)getMeshDimension()+1.);
3635 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3636 array->alloc(nbNodes,1);
3637 double *valsToFill=array->getPointer();
3638 std::fill(valsToFill,valsToFill+nbNodes,0.);
3639 const double *values=tmp->getArray()->getConstPointer();
3640 MCAuto<DataArrayInt> da=DataArrayInt::New();
3641 MCAuto<DataArrayInt> daInd=DataArrayInt::New();
3642 getReverseNodalConnectivity(da,daInd);
3643 const int *daPtr=da->getConstPointer();
3644 const int *daIPtr=daInd->getConstPointer();
3645 for(int i=0;i<nbNodes;i++)
3646 for(const int *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3647 valsToFill[i]+=cst*values[*cell];
3649 ret->setArray(array);
3654 * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3655 * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3656 * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3657 * and are normalized.
3658 * <br> \a this can be either
3659 * - a 2D mesh in 2D or 3D space or
3660 * - an 1D mesh in 2D space.
3662 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3663 * cells and one time. The caller is to delete this field using decrRef() as
3664 * it is no more needed.
3665 * \throw If the nodal connectivity of cells is not defined.
3666 * \throw If the coordinates array is not set.
3667 * \throw If the mesh dimension is not set.
3668 * \throw If the mesh and space dimension is not as specified above.
3670 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3672 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3673 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3674 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3675 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3676 int nbOfCells=getNumberOfCells();
3677 int nbComp=getMeshDimension()+1;
3678 array->alloc(nbOfCells,nbComp);
3679 double *vals=array->getPointer();
3680 const int *connI=_nodal_connec_index->getConstPointer();
3681 const int *conn=_nodal_connec->getConstPointer();
3682 const double *coords=_coords->getConstPointer();
3683 if(getMeshDimension()==2)
3685 if(getSpaceDimension()==3)
3687 MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3688 const double *locPtr=loc->getConstPointer();
3689 for(int i=0;i<nbOfCells;i++,vals+=3)
3691 int offset=connI[i];
3692 INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3693 double n=INTERP_KERNEL::norm<3>(vals);
3694 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3699 MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3700 const double *isAbsPtr=isAbs->getArray()->begin();
3701 for(int i=0;i<nbOfCells;i++,isAbsPtr++)
3702 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3705 else//meshdimension==1
3708 for(int i=0;i<nbOfCells;i++)
3710 int offset=connI[i];
3711 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3712 double n=INTERP_KERNEL::norm<2>(tmp);
3713 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3718 ret->setArray(array);
3720 ret->synchronizeTimeWithSupport();
3725 * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3726 * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3727 * and are normalized.
3728 * <br> \a this can be either
3729 * - a 2D mesh in 2D or 3D space or
3730 * - an 1D mesh in 2D space.
3732 * This method avoids building explicitly a part of \a this mesh to perform the work.
3733 * \param [in] begin - an array of cell ids of interest.
3734 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3735 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3736 * cells and one time. The caller is to delete this field using decrRef() as
3737 * it is no more needed.
3738 * \throw If the nodal connectivity of cells is not defined.
3739 * \throw If the coordinates array is not set.
3740 * \throw If the mesh dimension is not set.
3741 * \throw If the mesh and space dimension is not as specified above.
3742 * \sa buildOrthogonalField()
3744 * \if ENABLE_EXAMPLES
3745 * \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3746 * \ref py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3749 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const int *begin, const int *end) const
3751 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3752 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3753 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3754 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3755 std::size_t nbelems=std::distance(begin,end);
3756 int nbComp=getMeshDimension()+1;
3757 array->alloc((int)nbelems,nbComp);
3758 double *vals=array->getPointer();
3759 const int *connI=_nodal_connec_index->getConstPointer();
3760 const int *conn=_nodal_connec->getConstPointer();
3761 const double *coords=_coords->getConstPointer();
3762 if(getMeshDimension()==2)
3764 if(getSpaceDimension()==3)
3766 MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3767 const double *locPtr=loc->getConstPointer();
3768 for(const int *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3770 int offset=connI[*i];
3771 INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3772 double n=INTERP_KERNEL::norm<3>(vals);
3773 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3778 for(std::size_t i=0;i<nbelems;i++)
3779 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3782 else//meshdimension==1
3785 for(const int *i=begin;i!=end;i++)
3787 int offset=connI[*i];
3788 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3789 double n=INTERP_KERNEL::norm<2>(tmp);
3790 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3795 ret->setArray(array);
3797 ret->synchronizeTimeWithSupport();
3802 * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3803 * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3804 * and are \b not normalized.
3805 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3806 * cells and one time. The caller is to delete this field using decrRef() as
3807 * it is no more needed.
3808 * \throw If the nodal connectivity of cells is not defined.
3809 * \throw If the coordinates array is not set.
3810 * \throw If \a this->getMeshDimension() != 1.
3811 * \throw If \a this mesh includes cells of type other than SEG2.
3813 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3815 if(getMeshDimension()!=1)
3816 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3817 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3818 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3819 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3820 MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3821 int nbOfCells=getNumberOfCells();
3822 int spaceDim=getSpaceDimension();
3823 array->alloc(nbOfCells,spaceDim);
3824 double *pt=array->getPointer();
3825 const double *coo=getCoords()->getConstPointer();
3826 std::vector<int> conn;
3828 for(int i=0;i<nbOfCells;i++)
3831 getNodeIdsOfCell(i,conn);
3832 pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3834 ret->setArray(array);
3836 ret->synchronizeTimeWithSupport();
3841 * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3842 * returns a new DataArrayInt, of length equal to the number of 2D cells in the result
3843 * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3844 * from. If a result face is shared by two 3D cells, then the face in included twice in
3846 * \param [in] origin - 3 components of a point defining location of the plane.
3847 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3848 * must be greater than 1e-6.
3849 * \param [in] eps - half-thickness of the plane.
3850 * \param [out] cellIds - a new instance of DataArrayInt holding ids of 3D cells
3851 * producing correspondent 2D cells. The caller is to delete this array
3852 * using decrRef() as it is no more needed.
3853 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3854 * not share the node coordinates array with \a this mesh. The caller is to
3855 * delete this mesh using decrRef() as it is no more needed.
3856 * \throw If the coordinates array is not set.
3857 * \throw If the nodal connectivity of cells is not defined.
3858 * \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3859 * \throw If magnitude of \a vec is less than 1e-6.
3860 * \throw If the plane does not intersect any 3D cell of \a this mesh.
3861 * \throw If \a this includes quadratic cells.
3863 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3865 checkFullyDefined();
3866 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3867 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3868 MCAuto<DataArrayInt> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3869 if(candidates->empty())
3870 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3871 std::vector<int> nodes;
3872 DataArrayInt *cellIds1D=0;
3873 MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3874 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3875 MCAuto<DataArrayInt> desc1=DataArrayInt::New(),desc2=DataArrayInt::New();
3876 MCAuto<DataArrayInt> descIndx1=DataArrayInt::New(),descIndx2=DataArrayInt::New();
3877 MCAuto<DataArrayInt> revDesc1=DataArrayInt::New(),revDesc2=DataArrayInt::New();
3878 MCAuto<DataArrayInt> revDescIndx1=DataArrayInt::New(),revDescIndx2=DataArrayInt::New();
3879 MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3880 revDesc2=0; revDescIndx2=0;
3881 MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3882 revDesc1=0; revDescIndx1=0;
3883 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3884 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3886 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3887 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3889 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3890 std::vector< std::pair<int,int> > cut3DSurf(mDesc2->getNumberOfCells());
3891 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3892 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3893 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3894 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New());
3895 connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3896 subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3897 if(cellIds2->empty())
3898 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3899 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3900 ret->setCoords(mDesc1->getCoords());
3901 ret->setConnectivity(conn,connI,true);
3902 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3907 * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3908 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
3909 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3911 * \param [in] origin - 3 components of a point defining location of the plane.
3912 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3913 * must be greater than 1e-6.
3914 * \param [in] eps - half-thickness of the plane.
3915 * \param [out] cellIds - a new instance of DataArrayInt holding ids of faces
3916 * producing correspondent segments. The caller is to delete this array
3917 * using decrRef() as it is no more needed.
3918 * \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3919 * mesh in 3D space. This mesh does not share the node coordinates array with
3920 * \a this mesh. The caller is to delete this mesh using decrRef() as it is
3922 * \throw If the coordinates array is not set.
3923 * \throw If the nodal connectivity of cells is not defined.
3924 * \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3925 * \throw If magnitude of \a vec is less than 1e-6.
3926 * \throw If the plane does not intersect any 2D cell of \a this mesh.
3927 * \throw If \a this includes quadratic cells.
3929 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3931 checkFullyDefined();
3932 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3933 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3934 MCAuto<DataArrayInt> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3935 if(candidates->empty())
3936 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3937 std::vector<int> nodes;
3938 DataArrayInt *cellIds1D=0;
3939 MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3940 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3941 MCAuto<DataArrayInt> desc1=DataArrayInt::New();
3942 MCAuto<DataArrayInt> descIndx1=DataArrayInt::New();
3943 MCAuto<DataArrayInt> revDesc1=DataArrayInt::New();
3944 MCAuto<DataArrayInt> revDescIndx1=DataArrayInt::New();
3945 MCAuto<MEDCouplingUMesh> mDesc1=subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3946 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3947 MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3949 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3950 for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3952 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3953 int ncellsSub=subMesh->getNumberOfCells();
3954 std::vector< std::pair<int,int> > cut3DSurf(ncellsSub);
3955 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3956 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3957 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3958 MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New()); connI->pushBackSilent(0);
3960 const int *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3961 const int *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3962 for(int i=0;i<ncellsSub;i++)
3964 if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3966 if(cut3DSurf[i].first!=-2)
3968 conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3969 connI->pushBackSilent(conn->getNumberOfTuples());
3970 cellIds2->pushBackSilent(i);
3974 int cellId3DSurf=cut3DSurf[i].second;
3975 int offset=nodalI[cellId3DSurf]+1;
3976 int nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3977 for(int j=0;j<nbOfEdges;j++)
3979 conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3980 connI->pushBackSilent(conn->getNumberOfTuples());
3981 cellIds2->pushBackSilent(cellId3DSurf);
3986 if(cellIds2->empty())
3987 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3988 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3989 ret->setCoords(mDesc1->getCoords());
3990 ret->setConnectivity(conn,connI,true);
3991 cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3996 * Finds cells whose bounding boxes intersect a given plane.
3997 * \param [in] origin - 3 components of a point defining location of the plane.
3998 * \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3999 * must be greater than 1e-6.
4000 * \param [in] eps - half-thickness of the plane.
4001 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of the found
4002 * cells. The caller is to delete this array using decrRef() as it is no more
4004 * \throw If the coordinates array is not set.
4005 * \throw If the nodal connectivity of cells is not defined.
4006 * \throw If \a this->getSpaceDimension() != 3.
4007 * \throw If magnitude of \a vec is less than 1e-6.
4008 * \sa buildSlice3D()
4010 DataArrayInt *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
4012 checkFullyDefined();
4013 if(getSpaceDimension()!=3)
4014 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
4015 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
4017 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
4019 vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
4020 double angle=acos(vec[2]/normm);
4021 MCAuto<DataArrayInt> cellIds;
4025 MCAuto<DataArrayDouble> coo=_coords->deepCopy();
4026 double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
4027 if(normm2/normm>1e-6)
4028 MEDCouplingPointSet::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer());
4029 MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
4031 mw->getBoundingBox(bbox);
4032 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
4033 cellIds=mw->getCellsInBoundingBox(bbox,eps);
4037 getBoundingBox(bbox);
4038 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
4039 cellIds=getCellsInBoundingBox(bbox,eps);
4041 return cellIds.retn();
4045 * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
4046 * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
4047 * No consideration of coordinate is done by this method.
4048 * 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)
4049 * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be usefull.
4051 bool MEDCouplingUMesh::isContiguous1D() const
4053 if(getMeshDimension()!=1)
4054 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
4055 int nbCells=getNumberOfCells();
4057 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
4058 const int *connI=_nodal_connec_index->getConstPointer();
4059 const int *conn=_nodal_connec->getConstPointer();
4060 int ref=conn[connI[0]+2];
4061 for(int i=1;i<nbCells;i++)
4063 if(conn[connI[i]+1]!=ref)
4065 ref=conn[connI[i]+2];
4071 * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
4072 * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
4073 * \param pt reference point of the line
4074 * \param v normalized director vector of the line
4075 * \param eps max precision before throwing an exception
4076 * \param res output of size this->getNumberOfCells
4078 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
4080 if(getMeshDimension()!=1)
4081 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
4082 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
4083 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
4084 if(getSpaceDimension()!=3)
4085 throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
4086 MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
4087 const double *fPtr=f->getArray()->getConstPointer();
4089 for(int i=0;i<getNumberOfCells();i++)
4091 const double *tmp1=fPtr+3*i;
4092 tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
4093 tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
4094 tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
4095 double n1=INTERP_KERNEL::norm<3>(tmp);
4096 n1/=INTERP_KERNEL::norm<3>(tmp1);
4098 throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
4100 const double *coo=getCoords()->getConstPointer();
4101 for(int i=0;i<getNumberOfNodes();i++)
4103 std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
4104 std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
4105 res[i]=std::accumulate(tmp,tmp+3,0.);
4110 * 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.
4111 * \a this is expected to be a mesh so that its space dimension is equal to its
4112 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4113 * 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).
4115 * 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
4116 * 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).
4117 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4119 * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
4120 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4122 * \param [in] ptBg the start pointer (included) of the coordinates of the point
4123 * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
4124 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4125 * \return the positive value of the distance.
4126 * \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
4128 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
4130 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, int& cellId) const
4132 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4133 if(meshDim!=spaceDim-1)
4134 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
4135 if(meshDim!=2 && meshDim!=1)
4136 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
4137 checkFullyDefined();
4138 if((int)std::distance(ptBg,ptEnd)!=spaceDim)
4139 { 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()); }
4140 DataArrayInt *ret1=0;
4141 MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,C_DEALLOC,1,spaceDim);
4142 MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
4143 MCAuto<DataArrayInt> ret1Safe(ret1);
4144 cellId=*ret1Safe->begin();
4145 return *ret0->begin();
4149 * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
4150 * to \a this and the first \a cellId in \a this corresponding to the returned distance.
4151 * 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
4152 * 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).
4153 * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4155 * \a this is expected to be a mesh so that its space dimension is equal to its
4156 * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4157 * 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).
4159 * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
4160 * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4162 * \param [in] pts the list of points in which each tuple represents a point
4163 * \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.
4164 * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
4165 * \throw if number of components of \a pts is not equal to the space dimension.
4166 * \throw if mesh dimension of \a this is not equal to space dimension - 1.
4167 * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
4169 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayInt *& cellIds) const
4172 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
4173 pts->checkAllocated();
4174 int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4175 if(meshDim!=spaceDim-1)
4176 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
4177 if(meshDim!=2 && meshDim!=1)
4178 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
4179 if(pts->getNumberOfComponents()!=spaceDim)
4181 std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
4182 throw INTERP_KERNEL::Exception(oss.str());
4184 checkFullyDefined();
4185 int nbCells=getNumberOfCells();
4187 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
4188 int nbOfPts=pts->getNumberOfTuples();
4189 MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
4190 MCAuto<DataArrayInt> ret1=DataArrayInt::New(); ret1->alloc(nbOfPts,1);
4191 const int *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
4192 double *ret0Ptr=ret0->getPointer(); int *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
4193 MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
4194 const double *bbox(bboxArr->begin());
4199 BBTreeDst<3> myTree(bbox,0,0,nbCells);
4200 for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
4202 double x=std::numeric_limits<double>::max();
4203 std::vector<int> elems;
4204 myTree.getMinDistanceOfMax(ptsPtr,x);
4205 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4206 DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4212 BBTreeDst<2> myTree(bbox,0,0,nbCells);
4213 for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4215 double x=std::numeric_limits<double>::max();
4216 std::vector<int> elems;
4217 myTree.getMinDistanceOfMax(ptsPtr,x);
4218 myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4219 DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4224 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4226 cellIds=ret1.retn();
4233 * \param [in] pt the start pointer (included) of the coordinates of the point
4234 * \param [in] cellIdsBg the start pointer (included) of cellIds
4235 * \param [in] cellIdsEnd the end pointer (excluded) of cellIds
4236 * \param [in] nc nodal connectivity
4237 * \param [in] ncI nodal connectivity index
4238 * \param [in,out] ret0 the min distance between \a this and the external input point
4239 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4240 * \sa MEDCouplingUMesh::distanceToPoint, MEDCouplingUMesh::distanceToPoints
4242 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)
4245 ret0=std::numeric_limits<double>::max();
4246 for(const int *zeCell=cellIdsBg;zeCell!=cellIdsEnd;zeCell++)
4248 switch((INTERP_KERNEL::NormalizedCellType)nc[ncI[*zeCell]])
4250 case INTERP_KERNEL::NORM_TRI3:
4252 double tmp=INTERP_KERNEL::DistanceFromPtToTriInSpaceDim3(pt,coords+3*nc[ncI[*zeCell]+1],coords+3*nc[ncI[*zeCell]+2],coords+3*nc[ncI[*zeCell]+3]);
4254 { ret0=tmp; cellId=*zeCell; }
4257 case INTERP_KERNEL::NORM_QUAD4:
4258 case INTERP_KERNEL::NORM_POLYGON:
4260 double tmp=INTERP_KERNEL::DistanceFromPtToPolygonInSpaceDim3(pt,nc+ncI[*zeCell]+1,nc+ncI[*zeCell+1],coords);
4262 { ret0=tmp; cellId=*zeCell; }
4266 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint3DSurfAlg : not managed cell type ! Supporting TRI3, QUAD4 and POLYGON !");
4272 * \param [in] pt the start pointer (included) of the coordinates of the point
4273 * \param [in] cellIdsBg the start pointer (included) of cellIds
4274 * \param [in] cellIdsEnd the end pointer (excluded) of cellIds
4275 * \param [in] nc nodal connectivity
4276 * \param [in] ncI nodal connectivity index
4277 * \param [in,out] ret0 the min distance between \a this and the external input point
4278 * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4279 * \sa MEDCouplingUMesh::distanceToPoint, MEDCouplingUMesh::distanceToPoints
4281 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)
4284 ret0=std::numeric_limits<double>::max();
4285 for(const int *zeCell=cellIdsBg;zeCell!=cellIdsEnd;zeCell++)
4287 switch((INTERP_KERNEL::NormalizedCellType)nc[ncI[*zeCell]])
4289 case INTERP_KERNEL::NORM_SEG2:
4291 std::size_t uselessEntry=0;
4292 double tmp=INTERP_KERNEL::SquareDistanceFromPtToSegInSpaceDim2(pt,coords+2*nc[ncI[*zeCell]+1],coords+2*nc[ncI[*zeCell]+2],uselessEntry);
4295 { ret0=tmp; cellId=*zeCell; }
4299 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint2DCurveAlg : not managed cell type ! Supporting SEG2 !");
4306 * Finds cells in contact with a ball (i.e. a point with precision).
4307 * 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.
4308 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4310 * \warning This method is suitable if the caller intends to evaluate only one
4311 * point, for more points getCellsContainingPoints() is recommended as it is
4313 * \param [in] pos - array of coordinates of the ball central point.
4314 * \param [in] eps - ball radius.
4315 * \return int - a smallest id of cells being in contact with the ball, -1 in case
4316 * if there are no such cells.
4317 * \throw If the coordinates array is not set.
4318 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4320 int MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4322 std::vector<int> elts;
4323 getCellsContainingPoint(pos,eps,elts);
4326 return elts.front();
4330 * Finds cells in contact with a ball (i.e. a point with precision).
4331 * 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.
4332 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4333 * \warning This method is suitable if the caller intends to evaluate only one
4334 * point, for more points getCellsContainingPoints() is recommended as it is
4336 * \param [in] pos - array of coordinates of the ball central point.
4337 * \param [in] eps - ball radius.
4338 * \param [out] elts - vector returning ids of the found cells. It is cleared
4339 * before inserting ids.
4340 * \throw If the coordinates array is not set.
4341 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4343 * \if ENABLE_EXAMPLES
4344 * \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4345 * \ref py_mcumesh_getCellsContainingPoint "Here is a Python example".
4348 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<int>& elts) const
4350 MCAuto<DataArrayInt> eltsUg,eltsIndexUg;
4351 getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4352 elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4357 namespace MEDCoupling
4359 template<const int SPACEDIMM>
4363 static const int MY_SPACEDIM=SPACEDIMM;
4364 static const int MY_MESHDIM=8;
4365 typedef int MyConnType;
4366 static const INTERP_KERNEL::NumberingPolicy My_numPol=INTERP_KERNEL::ALL_C_MODE;
4368 // useless, but for windows compilation ...
4369 const double* getCoordinatesPtr() const { return 0; }
4370 const int* getConnectivityPtr() const { return 0; }
4371 const int* getConnectivityIndexPtr() const { return 0; }
4372 INTERP_KERNEL::NormalizedCellType getTypeOfElement(int) const { return (INTERP_KERNEL::NormalizedCellType)0; }
4376 INTERP_KERNEL::Edge *MEDCouplingUMeshBuildQPFromEdge2(INTERP_KERNEL::NormalizedCellType typ, const int *bg, const double *coords2D, std::map< MCAuto<INTERP_KERNEL::Node>,int>& m)
4378 INTERP_KERNEL::Edge *ret(0);
4379 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]));
4380 m[n0]=bg[0]; m[n1]=bg[1];
4383 case INTERP_KERNEL::NORM_SEG2:
4385 ret=new INTERP_KERNEL::EdgeLin(n0,n1);
4388 case INTERP_KERNEL::NORM_SEG3:
4390 INTERP_KERNEL::Node *n2(new INTERP_KERNEL::Node(coords2D[2*bg[2]],coords2D[2*bg[2]+1])); m[n2]=bg[2];
4391 INTERP_KERNEL::EdgeLin *e1(new INTERP_KERNEL::EdgeLin(n0,n2)),*e2(new INTERP_KERNEL::EdgeLin(n2,n1));
4392 INTERP_KERNEL::SegSegIntersector inters(*e1,*e2);
4393 // is the SEG3 degenerated, and thus can be reduced to a SEG2?
4394 bool colinearity(inters.areColinears());
4395 delete e1; delete e2;
4397 { ret=new INTERP_KERNEL::EdgeLin(n0,n1); }
4399 { ret=new INTERP_KERNEL::EdgeArcCircle(n0,n2,n1); }
4403 throw INTERP_KERNEL::Exception("MEDCouplingUMeshBuildQPFromEdge2 : Expecting a mesh with spaceDim==2 and meshDim==1 !");
4408 INTERP_KERNEL::Edge *MEDCouplingUMeshBuildQPFromEdge(INTERP_KERNEL::NormalizedCellType typ, std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >& mapp2, const int *bg)
4410 INTERP_KERNEL::Edge *ret=0;
4413 case INTERP_KERNEL::NORM_SEG2:
4415 ret=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[1]].first);
4418 case INTERP_KERNEL::NORM_SEG3:
4420 INTERP_KERNEL::EdgeLin *e1=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[2]].first);
4421 INTERP_KERNEL::EdgeLin *e2=new INTERP_KERNEL::EdgeLin(mapp2[bg[2]].first,mapp2[bg[1]].first);
4422 INTERP_KERNEL::SegSegIntersector inters(*e1,*e2);
4423 // is the SEG3 degenerated, and thus can be reduced to a SEG2?
4424 bool colinearity=inters.areColinears();
4425 delete e1; delete e2;
4427 ret=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[1]].first);
4429 ret=new INTERP_KERNEL::EdgeArcCircle(mapp2[bg[0]].first,mapp2[bg[2]].first,mapp2[bg[1]].first);
4430 mapp2[bg[2]].second=false;
4434 throw INTERP_KERNEL::Exception("MEDCouplingUMeshBuildQPFromEdge : Expecting a mesh with spaceDim==2 and meshDim==1 !");
4440 * This method creates a sub mesh in Geometric2D DS. The sub mesh is composed by the sub set of cells in 'candidates' taken from
4441 * the global mesh 'mDesc'.
4442 * The input mesh 'mDesc' must be so that mDim==1 and spaceDim==2.
4443 * 'mapp' returns a mapping between local numbering in submesh (represented by a Node*) and the global node numbering in 'mDesc'.
4445 INTERP_KERNEL::QuadraticPolygon *MEDCouplingUMeshBuildQPFromMesh(const MEDCouplingUMesh *mDesc, const std::vector<int>& candidates,
4446 std::map<INTERP_KERNEL::Node *,int>& mapp)
4449 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.
4450 const double *coo=mDesc->getCoords()->getConstPointer();
4451 const int *c=mDesc->getNodalConnectivity()->getConstPointer();
4452 const int *cI=mDesc->getNodalConnectivityIndex()->getConstPointer();
4454 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
4455 s.insert(c+cI[*it]+1,c+cI[(*it)+1]);
4456 for(std::set<int>::const_iterator it2=s.begin();it2!=s.end();it2++)
4458 INTERP_KERNEL::Node *n=new INTERP_KERNEL::Node(coo[2*(*it2)],coo[2*(*it2)+1]);
4459 mapp2[*it2]=std::pair<INTERP_KERNEL::Node *,bool>(n,true);
4461 INTERP_KERNEL::QuadraticPolygon *ret=new INTERP_KERNEL::QuadraticPolygon;
4462 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
4464 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[*it]];
4465 ret->pushBack(MEDCouplingUMeshBuildQPFromEdge(typ,mapp2,c+cI[*it]+1));
4467 for(std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >::const_iterator it2=mapp2.begin();it2!=mapp2.end();it2++)
4469 if((*it2).second.second)
4470 mapp[(*it2).second.first]=(*it2).first;
4471 ((*it2).second.first)->decrRef();
4476 INTERP_KERNEL::Node *MEDCouplingUMeshBuildQPNode(int nodeId, const double *coo1, int offset1, const double *coo2, int offset2, const std::vector<double>& addCoo)
4480 int locId=nodeId-offset2;
4481 return new INTERP_KERNEL::Node(addCoo[2*locId],addCoo[2*locId+1]);
4485 int locId=nodeId-offset1;
4486 return new INTERP_KERNEL::Node(coo2[2*locId],coo2[2*locId+1]);
4488 return new INTERP_KERNEL::Node(coo1[2*nodeId],coo1[2*nodeId+1]);
4492 * Construct a mapping between set of Nodes and the standart MEDCoupling connectivity format (c, cI).
4494 void MEDCouplingUMeshBuildQPFromMesh3(const double *coo1, int offset1, const double *coo2, int offset2, const std::vector<double>& addCoo,
4495 const int *desc1Bg, const int *desc1End, const std::vector<std::vector<int> >& intesctEdges1,
4496 /*output*/std::map<INTERP_KERNEL::Node *,int>& mapp, std::map<int,INTERP_KERNEL::Node *>& mappRev)
4498 for(const int *desc1=desc1Bg;desc1!=desc1End;desc1++)
4500 int eltId1=abs(*desc1)-1;
4501 for(std::vector<int>::const_iterator it1=intesctEdges1[eltId1].begin();it1!=intesctEdges1[eltId1].end();it1++)
4503 std::map<int,INTERP_KERNEL::Node *>::const_iterator it=mappRev.find(*it1);
4504 if(it==mappRev.end())
4506 INTERP_KERNEL::Node *node=MEDCouplingUMeshBuildQPNode(*it1,coo1,offset1,coo2,offset2,addCoo);
4517 template<int SPACEDIM>
4518 void MEDCouplingUMesh::getCellsContainingPointsAlg(const double *coords, const double *pos, int nbOfPoints,
4519 double eps, MCAuto<DataArrayInt>& elts, MCAuto<DataArrayInt>& eltsIndex) const
4521 elts=DataArrayInt::New(); eltsIndex=DataArrayInt::New(); eltsIndex->alloc(nbOfPoints+1,1); eltsIndex->setIJ(0,0,0); elts->alloc(0,1);
4522 int *eltsIndexPtr(eltsIndex->getPointer());
4523 MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree(eps));
4524 const double *bbox(bboxArr->begin());
4525 int nbOfCells=getNumberOfCells();
4526 const int *conn=_nodal_connec->getConstPointer();
4527 const int *connI=_nodal_connec_index->getConstPointer();
4528 double bb[2*SPACEDIM];
4529 BBTree<SPACEDIM,int> myTree(&bbox[0],0,0,nbOfCells,-eps);
4530 for(int i=0;i<nbOfPoints;i++)
4532 eltsIndexPtr[i+1]=eltsIndexPtr[i];
4533 for(int j=0;j<SPACEDIM;j++)
4535 bb[2*j]=pos[SPACEDIM*i+j];
4536 bb[2*j+1]=pos[SPACEDIM*i+j];
4538 std::vector<int> candidates;
4539 myTree.getIntersectingElems(bb,candidates);
4540 for(std::vector<int>::const_iterator iter=candidates.begin();iter!=candidates.end();iter++)
4542 int sz(connI[(*iter)+1]-connI[*iter]-1);
4543 INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[connI[*iter]]);
4545 if(ct!=INTERP_KERNEL::NORM_POLYGON && ct!=INTERP_KERNEL::NORM_QPOLYG)
4546 status=INTERP_KERNEL::PointLocatorAlgos<DummyClsMCUG<SPACEDIM> >::isElementContainsPoint(pos+i*SPACEDIM,ct,coords,conn+connI[*iter]+1,sz,eps);
4550 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPointsAlg : not implemented yet for POLYGON and QPOLYGON in spaceDim 3 !");
4551 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
4552 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
4553 std::vector<INTERP_KERNEL::Node *> nodes(sz);
4554 INTERP_KERNEL::QuadraticPolygon *pol(0);
4555 for(int j=0;j<sz;j++)
4557 int nodeId(conn[connI[*iter]+1+j]);
4558 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*SPACEDIM],coords[nodeId*SPACEDIM+1]);
4560 if(!INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic())
4561 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
4563 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
4564 INTERP_KERNEL::Node *n(new INTERP_KERNEL::Node(pos[i*SPACEDIM],pos[i*SPACEDIM+1]));
4565 double a(0.),b(0.),c(0.);
4566 a=pol->normalizeMe(b,c); n->applySimilarity(b,c,a);
4567 status=pol->isInOrOut2(n);
4568 delete pol; n->decrRef();
4572 eltsIndexPtr[i+1]++;
4573 elts->pushBackSilent(*iter);
4579 * Finds cells in contact with several balls (i.e. points with precision).
4580 * This method is an extension of getCellContainingPoint() and
4581 * getCellsContainingPoint() for the case of multiple points.
4582 * 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.
4583 * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4584 * \param [in] pos - an array of coordinates of points in full interlace mode :
4585 * X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4586 * this->getSpaceDimension() * \a nbOfPoints
4587 * \param [in] nbOfPoints - number of points to locate within \a this mesh.
4588 * \param [in] eps - radius of balls (i.e. the precision).
4589 * \param [out] elts - vector returning ids of found cells.
4590 * \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4591 * dividing cell ids in \a elts into groups each referring to one
4592 * point. Its every element (except the last one) is an index pointing to the
4593 * first id of a group of cells. For example cells in contact with the *i*-th
4594 * point are described by following range of indices:
4595 * [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4596 * \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4597 * Number of cells in contact with the *i*-th point is
4598 * \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4599 * \throw If the coordinates array is not set.
4600 * \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4602 * \if ENABLE_EXAMPLES
4603 * \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4604 * \ref py_mcumesh_getCellsContainingPoints "Here is a Python example".
4607 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, int nbOfPoints, double eps,
4608 MCAuto<DataArrayInt>& elts, MCAuto<DataArrayInt>& eltsIndex) const
4610 int spaceDim=getSpaceDimension();
4611 int mDim=getMeshDimension();
4616 const double *coords=_coords->getConstPointer();
4617 getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4624 throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4626 else if(spaceDim==2)
4630 const double *coords=_coords->getConstPointer();
4631 getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4634 throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4636 else if(spaceDim==1)
4640 const double *coords=_coords->getConstPointer();
4641 getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4644 throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4647 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4651 * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4652 * least two its edges intersect each other anywhere except their extremities. An
4653 * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4654 * \param [in,out] cells - a vector returning ids of the found cells. It is not
4655 * cleared before filling in.
4656 * \param [in] eps - precision.
4657 * \throw If \a this->getMeshDimension() != 2.
4658 * \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4660 void MEDCouplingUMesh::checkButterflyCells(std::vector<int>& cells, double eps) const
4662 const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4663 if(getMeshDimension()!=2)
4664 throw INTERP_KERNEL::Exception(msg);
4665 int spaceDim=getSpaceDimension();
4666 if(spaceDim!=2 && spaceDim!=3)
4667 throw INTERP_KERNEL::Exception(msg);
4668 const int *conn=_nodal_connec->getConstPointer();
4669 const int *connI=_nodal_connec_index->getConstPointer();
4670 int nbOfCells=getNumberOfCells();
4671 std::vector<double> cell2DinS2;
4672 for(int i=0;i<nbOfCells;i++)
4674 int offset=connI[i];
4675 int nbOfNodesForCell=connI[i+1]-offset-1;
4676 if(nbOfNodesForCell<=3)
4678 bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4679 project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4680 if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4687 * This method is typically requested to unbutterfly 2D linear cells in \b this.
4689 * 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.
4690 * 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.
4692 * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4693 * This convex envelop is computed using Jarvis march algorithm.
4694 * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4695 * 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)
4696 * 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.
4698 * \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.
4699 * \sa MEDCouplingUMesh::colinearize2D
4701 DataArrayInt *MEDCouplingUMesh::convexEnvelop2D()
4703 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4704 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D works only for meshDim=2 and spaceDim=2 !");
4705 checkFullyDefined();
4706 const double *coords=getCoords()->getConstPointer();
4707 int nbOfCells=getNumberOfCells();
4708 MCAuto<DataArrayInt> nodalConnecIndexOut=DataArrayInt::New();
4709 nodalConnecIndexOut->alloc(nbOfCells+1,1);
4710 MCAuto<DataArrayInt> nodalConnecOut(DataArrayInt::New());
4711 int *workIndexOut=nodalConnecIndexOut->getPointer();
4713 const int *nodalConnecIn=_nodal_connec->getConstPointer();
4714 const int *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4715 std::set<INTERP_KERNEL::NormalizedCellType> types;
4716 MCAuto<DataArrayInt> isChanged(DataArrayInt::New());
4717 isChanged->alloc(0,1);
4718 for(int i=0;i<nbOfCells;i++,workIndexOut++)
4720 int pos=nodalConnecOut->getNumberOfTuples();
4721 if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4722 isChanged->pushBackSilent(i);
4723 types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4724 workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4726 if(isChanged->empty())
4728 setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4730 return isChanged.retn();
4734 * This method is \b NOT const because it can modify \a this.
4735 * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4736 * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4737 * \param policy specifies the type of extrusion chosen:
4738 * - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4739 * will be repeated to build each level
4740 * - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4741 * 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
4742 * 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
4744 * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4746 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4748 checkFullyDefined();
4749 mesh1D->checkFullyDefined();
4750 if(!mesh1D->isContiguous1D())
4751 throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4752 if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4753 throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4754 if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4755 throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4756 if(mesh1D->getMeshDimension()!=1)
4757 throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4759 if(isPresenceOfQuadratic())
4761 if(mesh1D->isFullyQuadratic())
4764 throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4766 int oldNbOfNodes(getNumberOfNodes());
4767 MCAuto<DataArrayDouble> newCoords;
4772 newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4777 newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4781 throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4783 setCoords(newCoords);
4784 MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4790 * This method works on a 3D curve linear mesh that is to say (meshDim==1 and spaceDim==3).
4791 * If it is not the case an exception will be thrown.
4792 * This method is non const because the coordinate of \a this can be appended with some new points issued from
4793 * intersection of plane defined by ('origin','vec').
4794 * This method has one in/out parameter : 'cut3DCurve'.
4795 * Param 'cut3DCurve' is expected to be of size 'this->getNumberOfCells()'. For each i in [0,'this->getNumberOfCells()')
4796 * if cut3DCurve[i]==-2, it means that for cell #i in \a this nothing has been detected previously.
4797 * if cut3DCurve[i]==-1, it means that cell#i has been already detected to be fully part of plane defined by ('origin','vec').
4798 * This method will throw an exception if \a this contains a non linear segment.
4800 void MEDCouplingUMesh::split3DCurveWithPlane(const double *origin, const double *vec, double eps, std::vector<int>& cut3DCurve)
4802 checkFullyDefined();
4803 if(getMeshDimension()!=1 || getSpaceDimension()!=3)
4804 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane works on umeshes with meshdim equal to 1 and spaceDim equal to 3 !");
4805 int ncells=getNumberOfCells();
4806 int nnodes=getNumberOfNodes();
4807 double vec2[3],vec3[3],vec4[3];
4808 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
4810 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
4811 vec2[0]=vec[0]/normm; vec2[1]=vec[1]/normm; vec2[2]=vec[2]/normm;
4812 const int *conn=_nodal_connec->getConstPointer();
4813 const int *connI=_nodal_connec_index->getConstPointer();
4814 const double *coo=_coords->getConstPointer();
4815 std::vector<double> addCoo;
4816 for(int i=0;i<ncells;i++)
4818 if(conn[connI[i]]==(int)INTERP_KERNEL::NORM_SEG2)
4820 if(cut3DCurve[i]==-2)
4822 int st=conn[connI[i]+1],endd=conn[connI[i]+2];
4823 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];
4824 double normm2=sqrt(vec3[0]*vec3[0]+vec3[1]*vec3[1]+vec3[2]*vec3[2]);
4825 double colin=std::abs((vec3[0]*vec2[0]+vec3[1]*vec2[1]+vec3[2]*vec2[2])/normm2);
4826 if(colin>eps)//if colin<=eps -> current SEG2 is colinear to the input plane
4828 const double *st2=coo+3*st;
4829 vec4[0]=st2[0]-origin[0]; vec4[1]=st2[1]-origin[1]; vec4[2]=st2[2]-origin[2];
4830 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]));
4831 if(pos>eps && pos<1-eps)
4833 int nNode=((int)addCoo.size())/3;
4834 vec4[0]=st2[0]+pos*vec3[0]; vec4[1]=st2[1]+pos*vec3[1]; vec4[2]=st2[2]+pos*vec3[2];
4835 addCoo.insert(addCoo.end(),vec4,vec4+3);
4836 cut3DCurve[i]=nnodes+nNode;
4842 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane : this method is only available for linear cell (NORM_SEG2) !");
4846 int newNbOfNodes=nnodes+((int)addCoo.size())/3;
4847 MCAuto<DataArrayDouble> coo2=DataArrayDouble::New();
4848 coo2->alloc(newNbOfNodes,3);
4849 double *tmp=coo2->getPointer();
4850 tmp=std::copy(_coords->begin(),_coords->end(),tmp);
4851 std::copy(addCoo.begin(),addCoo.end(),tmp);
4852 DataArrayDouble::SetArrayIn(coo2,_coords);
4857 * This method incarnates the policy 0 for MEDCouplingUMesh::buildExtrudedMesh method.
4858 * \param mesh1D is the input 1D mesh used for translation computation.
4859 * \return newCoords new coords filled by this method.
4861 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslation(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4863 int oldNbOfNodes=getNumberOfNodes();
4864 int nbOf1DCells=mesh1D->getNumberOfCells();
4865 int spaceDim=getSpaceDimension();
4866 DataArrayDouble *ret=DataArrayDouble::New();
4867 std::vector<bool> isQuads;
4868 int nbOfLevsInVec=isQuad?2*nbOf1DCells+1:nbOf1DCells+1;
4869 ret->alloc(oldNbOfNodes*nbOfLevsInVec,spaceDim);
4870 double *retPtr=ret->getPointer();
4871 const double *coords=getCoords()->getConstPointer();
4872 double *work=std::copy(coords,coords+spaceDim*oldNbOfNodes,retPtr);
4874 std::vector<double> c;
4878 for(int i=0;i<nbOf1DCells;i++)
4881 mesh1D->getNodeIdsOfCell(i,v);
4883 mesh1D->getCoordinatesOfNode(v[isQuad?2:1],c);
4884 mesh1D->getCoordinatesOfNode(v[0],c);
4885 std::transform(c.begin(),c.begin()+spaceDim,c.begin()+spaceDim,vec,std::minus<double>());
4886 for(int j=0;j<oldNbOfNodes;j++)
4887 work=std::transform(vec,vec+spaceDim,retPtr+spaceDim*(i*oldNbOfNodes+j),work,std::plus<double>());
4891 mesh1D->getCoordinatesOfNode(v[1],c);
4892 mesh1D->getCoordinatesOfNode(v[0],c);
4893 std::transform(c.begin(),c.begin()+spaceDim,c.begin()+spaceDim,vec,std::minus<double>());
4894 for(int j=0;j<oldNbOfNodes;j++)
4895 work=std::transform(vec,vec+spaceDim,retPtr+spaceDim*(i*oldNbOfNodes+j),work,std::plus<double>());
4898 ret->copyStringInfoFrom(*getCoords());
4903 * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4904 * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4905 * \return newCoords new coords filled by this method.
4907 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4909 if(mesh1D->getSpaceDimension()==2)
4910 return fillExtCoordsUsingTranslAndAutoRotation2D(mesh1D,isQuad);
4911 if(mesh1D->getSpaceDimension()==3)
4912 return fillExtCoordsUsingTranslAndAutoRotation3D(mesh1D,isQuad);
4913 throw INTERP_KERNEL::Exception("Not implemented rotation and translation alg. for spacedim other than 2 and 3 !");
4917 * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4918 * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4919 * \return newCoords new coords filled by this method.
4921 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4924 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D : not implemented for quadratic cells !");
4925 int oldNbOfNodes=getNumberOfNodes();
4926 int nbOf1DCells=mesh1D->getNumberOfCells();
4928 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D : impossible to detect any angle of rotation ! Change extrusion policy 1->0 !");
4929 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
4930 int nbOfLevsInVec=nbOf1DCells+1;
4931 ret->alloc(oldNbOfNodes*nbOfLevsInVec,2);
4932 double *retPtr=ret->getPointer();
4933 retPtr=std::copy(getCoords()->getConstPointer(),getCoords()->getConstPointer()+getCoords()->getNbOfElems(),retPtr);
4934 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
4935 MCAuto<DataArrayDouble> tmp2=getCoords()->deepCopy();
4936 tmp->setCoords(tmp2);
4937 const double *coo1D=mesh1D->getCoords()->getConstPointer();
4938 const int *conn1D=mesh1D->getNodalConnectivity()->getConstPointer();
4939 const int *connI1D=mesh1D->getNodalConnectivityIndex()->getConstPointer();
4940 for(int i=1;i<nbOfLevsInVec;i++)
4942 const double *begin=coo1D+2*conn1D[connI1D[i-1]+1];
4943 const double *end=coo1D+2*conn1D[connI1D[i-1]+2];
4944 const double *third=i+1<nbOfLevsInVec?coo1D+2*conn1D[connI1D[i]+2]:coo1D+2*conn1D[connI1D[i-2]+1];
4945 const double vec[2]={end[0]-begin[0],end[1]-begin[1]};
4946 tmp->translate(vec);
4947 double tmp3[2],radius,alpha,alpha0;
4948 const double *p0=i+1<nbOfLevsInVec?begin:third;
4949 const double *p1=i+1<nbOfLevsInVec?end:begin;
4950 const double *p2=i+1<nbOfLevsInVec?third:end;
4951 INTERP_KERNEL::EdgeArcCircle::GetArcOfCirclePassingThru(p0,p1,p2,tmp3,radius,alpha,alpha0);
4952 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]);
4953 double angle=acos(cosangle/(radius*radius));
4954 tmp->rotate(end,0,angle);
4955 retPtr=std::copy(tmp2->getConstPointer(),tmp2->getConstPointer()+tmp2->getNbOfElems(),retPtr);
4961 * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4962 * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4963 * \return newCoords new coords filled by this method.
4965 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4968 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D : not implemented for quadratic cells !");
4969 int oldNbOfNodes=getNumberOfNodes();
4970 int nbOf1DCells=mesh1D->getNumberOfCells();
4972 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D : impossible to detect any angle of rotation ! Change extrusion policy 1->0 !");
4973 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
4974 int nbOfLevsInVec=nbOf1DCells+1;
4975 ret->alloc(oldNbOfNodes*nbOfLevsInVec,3);
4976 double *retPtr=ret->getPointer();
4977 retPtr=std::copy(getCoords()->getConstPointer(),getCoords()->getConstPointer()+getCoords()->getNbOfElems(),retPtr);
4978 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
4979 MCAuto<DataArrayDouble> tmp2=getCoords()->deepCopy();
4980 tmp->setCoords(tmp2);
4981 const double *coo1D=mesh1D->getCoords()->getConstPointer();
4982 const int *conn1D=mesh1D->getNodalConnectivity()->getConstPointer();
4983 const int *connI1D=mesh1D->getNodalConnectivityIndex()->getConstPointer();
4984 for(int i=1;i<nbOfLevsInVec;i++)
4986 const double *begin=coo1D+3*conn1D[connI1D[i-1]+1];
4987 const double *end=coo1D+3*conn1D[connI1D[i-1]+2];
4988 const double *third=i+1<nbOfLevsInVec?coo1D+3*conn1D[connI1D[i]+2]:coo1D+3*conn1D[connI1D[i-2]+1];
4989 const double vec[3]={end[0]-begin[0],end[1]-begin[1],end[2]-begin[2]};
4990 tmp->translate(vec);
4991 double tmp3[2],radius,alpha,alpha0;
4992 const double *p0=i+1<nbOfLevsInVec?begin:third;
4993 const double *p1=i+1<nbOfLevsInVec?end:begin;
4994 const double *p2=i+1<nbOfLevsInVec?third:end;
4995 double vecPlane[3]={
4996 (p1[1]-p0[1])*(p2[2]-p1[2])-(p1[2]-p0[2])*(p2[1]-p1[1]),
4997 (p1[2]-p0[2])*(p2[0]-p1[0])-(p1[0]-p0[0])*(p2[2]-p1[2]),
4998 (p1[0]-p0[0])*(p2[1]-p1[1])-(p1[1]-p0[1])*(p2[0]-p1[0]),
5000 double norm=sqrt(vecPlane[0]*vecPlane[0]+vecPlane[1]*vecPlane[1]+vecPlane[2]*vecPlane[2]);
5003 vecPlane[0]/=norm; vecPlane[1]/=norm; vecPlane[2]/=norm;
5004 double norm2=sqrt(vecPlane[0]*vecPlane[0]+vecPlane[1]*vecPlane[1]);
5005 double vec2[2]={vecPlane[1]/norm2,-vecPlane[0]/norm2};
5007 double c2=cos(asin(s2));
5009 {vec2[0]*vec2[0]*(1-c2)+c2, vec2[0]*vec2[1]*(1-c2), vec2[1]*s2},
5010 {vec2[0]*vec2[1]*(1-c2), vec2[1]*vec2[1]*(1-c2)+c2, -vec2[0]*s2},
5011 {-vec2[1]*s2, vec2[0]*s2, c2}
5013 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]};
5014 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]};
5015 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]};
5016 INTERP_KERNEL::EdgeArcCircle::GetArcOfCirclePassingThru(p0r,p1r,p2r,tmp3,radius,alpha,alpha0);
5017 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]);
5018 double angle=acos(cosangle/(radius*radius));
5019 tmp->rotate(end,vecPlane,angle);
5021 retPtr=std::copy(tmp2->getConstPointer(),tmp2->getConstPointer()+tmp2->getNbOfElems(),retPtr);
5027 * This method is private because not easy to use for end user. This method is const contrary to
5028 * MEDCouplingUMesh::buildExtrudedMesh method because this->_coords are expected to contain
5029 * the coords sorted slice by slice.
5030 * \param isQuad specifies presence of quadratic cells.
5032 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMeshFromThisLowLev(int nbOfNodesOf1Lev, bool isQuad) const
5034 int nbOf1DCells(getNumberOfNodes()/nbOfNodesOf1Lev-1);
5035 int nbOf2DCells(getNumberOfCells());
5036 int nbOf3DCells(nbOf2DCells*nbOf1DCells);
5037 MEDCouplingUMesh *ret(MEDCouplingUMesh::New("Extruded",getMeshDimension()+1));
5038 const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5039 MCAuto<DataArrayInt> newConn(DataArrayInt::New()),newConnI(DataArrayInt::New());
5040 newConnI->alloc(nbOf3DCells+1,1);
5041 int *newConnIPtr(newConnI->getPointer());
5043 std::vector<int> newc;
5044 for(int j=0;j<nbOf2DCells;j++)
5046 AppendExtrudedCell(conn+connI[j],conn+connI[j+1],nbOfNodesOf1Lev,isQuad,newc);
5047 *newConnIPtr++=(int)newc.size();
5049 newConn->alloc((int)(newc.size())*nbOf1DCells,1);
5050 int *newConnPtr(newConn->getPointer());
5051 int deltaPerLev(isQuad?2*nbOfNodesOf1Lev:nbOfNodesOf1Lev);
5052 newConnIPtr=newConnI->getPointer();
5053 for(int iz=0;iz<nbOf1DCells;iz++)
5056 std::transform(newConnIPtr+1,newConnIPtr+1+nbOf2DCells,newConnIPtr+1+iz*nbOf2DCells,std::bind2nd(std::plus<int>(),newConnIPtr[iz*nbOf2DCells]));
5057 const int *posOfTypeOfCell(newConnIPtr);
5058 for(std::vector<int>::const_iterator iter=newc.begin();iter!=newc.end();iter++,newConnPtr++)
5060 int icell((int)(iter-newc.begin()));//std::distance unfortunately cannot been called here in C++98
5061 if(icell!=*posOfTypeOfCell)
5064 *newConnPtr=(*iter)+iz*deltaPerLev;
5075 ret->setConnectivity(newConn,newConnI,true);
5076 ret->setCoords(getCoords());
5081 * Checks if \a this mesh is constituted by only quadratic cells.
5082 * \return bool - \c true if there are only quadratic cells in \a this mesh.
5083 * \throw If the coordinates array is not set.
5084 * \throw If the nodal connectivity of cells is not defined.
5086 bool MEDCouplingUMesh::isFullyQuadratic() const
5088 checkFullyDefined();
5090 int nbOfCells=getNumberOfCells();
5091 for(int i=0;i<nbOfCells && ret;i++)
5093 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5094 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5095 ret=cm.isQuadratic();
5101 * Checks if \a this mesh includes any quadratic cell.
5102 * \return bool - \c true if there is at least one quadratic cells in \a this mesh.
5103 * \throw If the coordinates array is not set.
5104 * \throw If the nodal connectivity of cells is not defined.
5106 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
5108 checkFullyDefined();
5110 int nbOfCells=getNumberOfCells();
5111 for(int i=0;i<nbOfCells && !ret;i++)
5113 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5114 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5115 ret=cm.isQuadratic();
5121 * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
5122 * this mesh, it remains unchanged.
5123 * \throw If the coordinates array is not set.
5124 * \throw If the nodal connectivity of cells is not defined.
5126 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
5128 checkFullyDefined();
5129 int nbOfCells=getNumberOfCells();
5131 const int *iciptr=_nodal_connec_index->getConstPointer();
5132 for(int i=0;i<nbOfCells;i++)
5134 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5135 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5136 if(cm.isQuadratic())
5138 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
5139 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
5140 if(!cml.isDynamic())
5141 delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
5143 delta+=(iciptr[i+1]-iciptr[i]-1)/2;
5148 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5149 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5150 const int *icptr=_nodal_connec->getConstPointer();
5151 newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
5152 newConnI->alloc(nbOfCells+1,1);
5153 int *ocptr=newConn->getPointer();
5154 int *ociptr=newConnI->getPointer();
5157 for(int i=0;i<nbOfCells;i++,ociptr++)
5159 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
5160 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5161 if(!cm.isQuadratic())
5163 _types.insert(type);
5164 ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
5165 ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
5169 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
5170 _types.insert(typel);
5171 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
5172 int newNbOfNodes=cml.getNumberOfNodes();
5174 newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
5175 *ocptr++=(int)typel;
5176 ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
5177 ociptr[1]=ociptr[0]+newNbOfNodes+1;
5180 setConnectivity(newConn,newConnI,false);
5184 * This method converts all linear cell in \a this to quadratic one.
5185 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
5186 * 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)
5187 * 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.
5188 * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
5189 * end of the existing coordinates.
5191 * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
5192 * corresponding quadratic cells. 1 is those creating the 'most' complex.
5193 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5195 * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
5197 * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
5199 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
5201 DataArrayInt *conn=0,*connI=0;
5202 DataArrayDouble *coords=0;
5203 std::set<INTERP_KERNEL::NormalizedCellType> types;
5204 checkFullyDefined();
5205 MCAuto<DataArrayInt> ret,connSafe,connISafe;
5206 MCAuto<DataArrayDouble> coordsSafe;
5207 int meshDim=getMeshDimension();
5208 switch(conversionType)
5214 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
5215 connSafe=conn; connISafe=connI; coordsSafe=coords;
5218 ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
5219 connSafe=conn; connISafe=connI; coordsSafe=coords;
5222 ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
5223 connSafe=conn; connISafe=connI; coordsSafe=coords;
5226 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
5234 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
5235 connSafe=conn; connISafe=connI; coordsSafe=coords;
5238 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
5239 connSafe=conn; connISafe=connI; coordsSafe=coords;
5242 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
5243 connSafe=conn; connISafe=connI; coordsSafe=coords;
5246 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
5251 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
5253 setConnectivity(connSafe,connISafe,false);
5255 setCoords(coordsSafe);
5260 * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
5261 * so that the number of cells remains the same. Quadratic faces are converted to
5262 * polygons. This method works only for 2D meshes in
5263 * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
5264 * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
5265 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5266 * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
5267 * a polylinized edge constituting the input polygon.
5268 * \throw If the coordinates array is not set.
5269 * \throw If the nodal connectivity of cells is not defined.
5270 * \throw If \a this->getMeshDimension() != 2.
5271 * \throw If \a this->getSpaceDimension() != 2.
5273 void MEDCouplingUMesh::tessellate2D(double eps)
5275 int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
5277 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
5281 return tessellate2DCurveInternal(eps);
5283 return tessellate2DInternal(eps);
5285 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
5289 * Tessellates \a this 1D mesh in 2D space by dividing not straight quadratic edges.
5290 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5291 * \param [in] eps - specifies the maximal angle (in radian) between 2 sub-edges of
5292 * a sub-divided edge.
5293 * \throw If the coordinates array is not set.
5294 * \throw If the nodal connectivity of cells is not defined.
5295 * \throw If \a this->getMeshDimension() != 1.
5296 * \throw If \a this->getSpaceDimension() != 2.
5301 * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
5302 * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
5303 * The nodes to be added in those 2D cells are defined by the pair of \a nodeIdsToAdd and \a nodeIdsIndexToAdd.
5304 * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
5305 * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
5306 * This method can be seen as the opposite method of colinearize2D.
5307 * 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
5308 * to avoid to modify the numbering of existing nodes.
5310 * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
5311 * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
5312 * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
5313 * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
5314 * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
5315 * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
5316 * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
5318 * \sa buildDescendingConnectivity2
5320 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayInt *nodeIdsToAdd, const DataArrayInt *nodeIdsIndexToAdd, const DataArrayInt *edgeIdsToBeSplit,
5321 const MEDCouplingUMesh *mesh1Desc, const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *revDesc, const DataArrayInt *revDescI)
5323 if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
5324 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
5325 nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
5326 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
5327 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
5328 if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
5329 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
5330 //DataArrayInt *out0(0),*outi0(0);
5331 //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
5332 //MCAuto<DataArrayInt> out0s(out0),outi0s(outi0);
5333 //out0s=out0s->buildUnique(); out0s->sort(true);
5338 * Implementes \a conversionType 0 for meshes with meshDim = 1, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5339 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5340 * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5342 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic1D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5344 MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5345 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5346 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5347 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5348 int nbOfCells=getNumberOfCells();
5349 int nbOfNodes=getNumberOfNodes();
5350 const int *cPtr=_nodal_connec->getConstPointer();
5351 const int *icPtr=_nodal_connec_index->getConstPointer();
5352 int lastVal=0,offset=nbOfNodes;
5353 for(int i=0;i<nbOfCells;i++,icPtr++)
5355 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5356 if(type==INTERP_KERNEL::NORM_SEG2)
5358 types.insert(INTERP_KERNEL::NORM_SEG3);
5359 newConn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG3);
5360 newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[0]+3);
5361 newConn->pushBackSilent(offset++);
5363 newConnI->pushBackSilent(lastVal);
5364 ret->pushBackSilent(i);
5369 lastVal+=(icPtr[1]-icPtr[0]);
5370 newConnI->pushBackSilent(lastVal);
5371 newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5374 MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5375 coords=DataArrayDouble::Aggregate(getCoords(),tmp); conn=newConn.retn(); connI=newConnI.retn();
5379 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
5381 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5382 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5383 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5385 const int *descPtr(desc->begin()),*descIPtr(descI->begin());
5386 DataArrayInt *conn1D=0,*conn1DI=0;
5387 std::set<INTERP_KERNEL::NormalizedCellType> types1D;
5388 DataArrayDouble *coordsTmp=0;
5389 MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=0;
5390 MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5391 MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5392 const int *c1DPtr=conn1D->begin();
5393 const int *c1DIPtr=conn1DI->begin();
5394 int nbOfCells=getNumberOfCells();
5395 const int *cPtr=_nodal_connec->getConstPointer();
5396 const int *icPtr=_nodal_connec_index->getConstPointer();
5398 for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++)
5400 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5401 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5402 if(!cm.isQuadratic())
5404 INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType();
5405 types.insert(typ2); newConn->pushBackSilent(typ2);
5406 newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5407 for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5408 newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5409 lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0]);
5410 newConnI->pushBackSilent(lastVal);
5411 ret->pushBackSilent(i);
5416 lastVal+=(icPtr[1]-icPtr[0]);
5417 newConnI->pushBackSilent(lastVal);
5418 newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5421 conn=newConn.retn(); connI=newConnI.retn(); coords=coordsTmpSafe.retn();
5426 * Implementes \a conversionType 0 for meshes with meshDim = 2, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5427 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5428 * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5430 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic2D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5432 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5433 MCAuto<MEDCouplingUMesh> m1D=buildDescendingConnectivity(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5434 return convertLinearCellsToQuadratic2DAnd3D0(m1D,desc,descI,conn,connI,coords,types);
5437 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic2D1(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5439 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5440 MCAuto<MEDCouplingUMesh> m1D=buildDescendingConnectivity(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5442 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5443 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5444 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5446 MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5447 const int *descPtr(desc->begin()),*descIPtr(descI->begin());
5448 DataArrayInt *conn1D=0,*conn1DI=0;
5449 std::set<INTERP_KERNEL::NormalizedCellType> types1D;
5450 DataArrayDouble *coordsTmp=0;
5451 MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=0;
5452 MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5453 MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5454 const int *c1DPtr=conn1D->begin();
5455 const int *c1DIPtr=conn1DI->begin();
5456 int nbOfCells=getNumberOfCells();
5457 const int *cPtr=_nodal_connec->getConstPointer();
5458 const int *icPtr=_nodal_connec_index->getConstPointer();
5459 int lastVal=0,offset=coordsTmpSafe->getNumberOfTuples();
5460 for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++)
5462 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5463 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5464 if(!cm.isQuadratic())
5466 INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType2();
5467 types.insert(typ2); newConn->pushBackSilent(typ2);
5468 newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5469 for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5470 newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5471 newConn->pushBackSilent(offset+ret->getNumberOfTuples());
5472 lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0])+1;
5473 newConnI->pushBackSilent(lastVal);
5474 ret->pushBackSilent(i);
5479 lastVal+=(icPtr[1]-icPtr[0]);
5480 newConnI->pushBackSilent(lastVal);
5481 newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5484 MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5485 coords=DataArrayDouble::Aggregate(coordsTmpSafe,tmp); conn=newConn.retn(); connI=newConnI.retn();
5490 * Implementes \a conversionType 0 for meshes with meshDim = 3, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5491 * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5492 * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5494 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic3D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5496 MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5497 MCAuto<MEDCouplingUMesh> m1D=explode3DMeshTo1D(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5498 return convertLinearCellsToQuadratic2DAnd3D0(m1D,desc,descI,conn,connI,coords,types);
5501 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic3D1(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5503 MCAuto<DataArrayInt> desc2(DataArrayInt::New()),desc2I(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5504 MCAuto<MEDCouplingUMesh> m2D=buildDescendingConnectivityGen<MinusOneSonsGeneratorBiQuadratic>(desc2,desc2I,tmp2,tmp3,MEDCouplingFastNbrer); tmp2=0; tmp3=0;
5505 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),desc1I(DataArrayInt::New()),tmp4(DataArrayInt::New()),tmp5(DataArrayInt::New());
5506 MCAuto<MEDCouplingUMesh> m1D=explode3DMeshTo1D(desc1,desc1I,tmp4,tmp5); tmp4=0; tmp5=0;
5508 MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5509 MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5510 MCAuto<DataArrayInt> ret=DataArrayInt::New(),ret2=DataArrayInt::New(); ret->alloc(0,1); ret2->alloc(0,1);
5512 MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5513 const int *descPtr(desc1->begin()),*descIPtr(desc1I->begin()),*desc2Ptr(desc2->begin()),*desc2IPtr(desc2I->begin());
5514 DataArrayInt *conn1D=0,*conn1DI=0,*conn2D=0,*conn2DI=0;
5515 std::set<INTERP_KERNEL::NormalizedCellType> types1D,types2D;
5516 DataArrayDouble *coordsTmp=0,*coordsTmp2=0;
5517 MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=DataArrayInt::New(); ret1D->alloc(0,1);
5518 MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5519 MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5520 MCAuto<DataArrayInt> ret2D=m2D->convertLinearCellsToQuadratic2D1(conn2D,conn2DI,coordsTmp2,types2D); ret2D=DataArrayInt::New(); ret2D->alloc(0,1);
5521 MCAuto<DataArrayDouble> coordsTmp2Safe(coordsTmp2);
5522 MCAuto<DataArrayInt> conn2DSafe(conn2D),conn2DISafe(conn2DI);
5523 const int *c1DPtr=conn1D->begin(),*c1DIPtr=conn1DI->begin(),*c2DPtr=conn2D->begin(),*c2DIPtr=conn2DI->begin();
5524 int nbOfCells=getNumberOfCells();
5525 const int *cPtr=_nodal_connec->getConstPointer();
5526 const int *icPtr=_nodal_connec_index->getConstPointer();
5527 int lastVal=0,offset=coordsTmpSafe->getNumberOfTuples();
5528 for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++,desc2IPtr++)
5530 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5531 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5532 if(!cm.isQuadratic())
5534 INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType2();
5535 if(typ2==INTERP_KERNEL::NORM_ERROR)
5537 std::ostringstream oss; oss << "MEDCouplingUMesh::convertLinearCellsToQuadratic3D1 : On cell #" << i << " the linear cell type does not support advanced quadratization !";
5538 throw INTERP_KERNEL::Exception(oss.str());
5540 types.insert(typ2); newConn->pushBackSilent(typ2);
5541 newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5542 for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5543 newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5544 for(const int *d=desc2Ptr+desc2IPtr[0];d!=desc2Ptr+desc2IPtr[1];d++)
5546 int nodeId2=c2DPtr[c2DIPtr[(*d)+1]-1];
5547 int tmpPos=newConn->getNumberOfTuples();
5548 newConn->pushBackSilent(nodeId2);
5549 ret2D->pushBackSilent(nodeId2); ret1D->pushBackSilent(tmpPos);
5551 newConn->pushBackSilent(offset+ret->getNumberOfTuples());
5552 lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0])+(desc2IPtr[1]-desc2IPtr[0])+1;
5553 newConnI->pushBackSilent(lastVal);
5554 ret->pushBackSilent(i);
5559 lastVal+=(icPtr[1]-icPtr[0]);
5560 newConnI->pushBackSilent(lastVal);
5561 newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5564 MCAuto<DataArrayInt> diffRet2D=ret2D->getDifferentValues();
5565 MCAuto<DataArrayInt> o2nRet2D=diffRet2D->invertArrayN2O2O2N(coordsTmp2Safe->getNumberOfTuples());
5566 coordsTmp2Safe=coordsTmp2Safe->selectByTupleId(diffRet2D->begin(),diffRet2D->end());
5567 MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5568 std::vector<const DataArrayDouble *> v(3); v[0]=coordsTmpSafe; v[1]=coordsTmp2Safe; v[2]=tmp;
5569 int *c=newConn->getPointer();
5570 const int *cI(newConnI->begin());
5571 for(const int *elt=ret1D->begin();elt!=ret1D->end();elt++)
5572 c[*elt]=o2nRet2D->getIJ(c[*elt],0)+offset;
5573 offset=coordsTmp2Safe->getNumberOfTuples();
5574 for(const int *elt=ret->begin();elt!=ret->end();elt++)
5575 c[cI[(*elt)+1]-1]+=offset;
5576 coords=DataArrayDouble::Aggregate(v); conn=newConn.retn(); connI=newConnI.retn();
5581 * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
5582 * In addition, returns an array mapping new cells to old ones. <br>
5583 * This method typically increases the number of cells in \a this mesh
5584 * but the number of nodes remains \b unchanged.
5585 * That's why the 3D splitting policies
5586 * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
5587 * \param [in] policy - specifies a pattern used for splitting.
5588 * The semantic of \a policy is:
5589 * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
5590 * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
5591 * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8 into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
5592 * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8 into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
5595 * \return DataArrayInt * - a new instance of DataArrayInt holding, for each new cell,
5596 * an id of old cell producing it. The caller is to delete this array using
5597 * decrRef() as it is no more needed.
5599 * \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
5600 * \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
5601 * and \a this->getMeshDimension() != 3.
5602 * \throw If \a policy is not one of the four discussed above.
5603 * \throw If the nodal connectivity of cells is not defined.
5604 * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
5606 DataArrayInt *MEDCouplingUMesh::simplexize(int policy)
5611 return simplexizePol0();
5613 return simplexizePol1();
5614 case (int) INTERP_KERNEL::PLANAR_FACE_5:
5615 return simplexizePlanarFace5();
5616 case (int) INTERP_KERNEL::PLANAR_FACE_6:
5617 return simplexizePlanarFace6();
5619 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)");
5624 * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
5625 * - 1D: INTERP_KERNEL::NORM_SEG2
5626 * - 2D: INTERP_KERNEL::NORM_TRI3
5627 * - 3D: INTERP_KERNEL::NORM_TETRA4.
5629 * This method is useful for users that need to use P1 field services as
5630 * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
5631 * All these methods need mesh support containing only simplex cells.
5632 * \return bool - \c true if there are only simplex cells in \a this mesh.
5633 * \throw If the coordinates array is not set.
5634 * \throw If the nodal connectivity of cells is not defined.
5635 * \throw If \a this->getMeshDimension() < 1.
5637 bool MEDCouplingUMesh::areOnlySimplexCells() const
5639 checkFullyDefined();
5640 int mdim=getMeshDimension();
5641 if(mdim<1 || mdim>3)
5642 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
5643 int nbCells=getNumberOfCells();
5644 const int *conn=_nodal_connec->getConstPointer();
5645 const int *connI=_nodal_connec_index->getConstPointer();
5646 for(int i=0;i<nbCells;i++)
5648 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5656 * This method implements policy 0 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5658 DataArrayInt *MEDCouplingUMesh::simplexizePol0()
5660 checkConnectivityFullyDefined();
5661 if(getMeshDimension()!=2)
5662 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePol0 : this policy is only available for mesh with meshdim == 2 !");
5663 int nbOfCells=getNumberOfCells();
5664 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5665 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_QUAD4);
5666 ret->alloc(nbOfCells+nbOfCutCells,1);
5667 if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5668 int *retPt=ret->getPointer();
5669 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5670 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5671 newConnI->alloc(nbOfCells+nbOfCutCells+1,1);
5672 newConn->alloc(getNodalConnectivityArrayLen()+3*nbOfCutCells,1);
5673 int *pt=newConn->getPointer();
5674 int *ptI=newConnI->getPointer();
5676 const int *oldc=_nodal_connec->getConstPointer();
5677 const int *ci=_nodal_connec_index->getConstPointer();
5678 for(int i=0;i<nbOfCells;i++,ci++)
5680 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_QUAD4)
5682 const int tmp[8]={(int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+2],oldc[ci[0]+3],
5683 (int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+3],oldc[ci[0]+4]};
5684 pt=std::copy(tmp,tmp+8,pt);
5693 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5694 ptI[1]=ptI[0]+ci[1]-ci[0];
5699 _nodal_connec->decrRef();
5700 _nodal_connec=newConn.retn();
5701 _nodal_connec_index->decrRef();
5702 _nodal_connec_index=newConnI.retn();
5709 * This method implements policy 1 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5711 DataArrayInt *MEDCouplingUMesh::simplexizePol1()
5713 checkConnectivityFullyDefined();
5714 if(getMeshDimension()!=2)
5715 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePol0 : this policy is only available for mesh with meshdim == 2 !");
5716 int nbOfCells=getNumberOfCells();
5717 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5718 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_QUAD4);
5719 ret->alloc(nbOfCells+nbOfCutCells,1);
5720 if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5721 int *retPt=ret->getPointer();
5722 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5723 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5724 newConnI->alloc(nbOfCells+nbOfCutCells+1,1);
5725 newConn->alloc(getNodalConnectivityArrayLen()+3*nbOfCutCells,1);
5726 int *pt=newConn->getPointer();
5727 int *ptI=newConnI->getPointer();
5729 const int *oldc=_nodal_connec->getConstPointer();
5730 const int *ci=_nodal_connec_index->getConstPointer();
5731 for(int i=0;i<nbOfCells;i++,ci++)
5733 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_QUAD4)
5735 const int tmp[8]={(int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+2],oldc[ci[0]+4],
5736 (int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+2],oldc[ci[0]+3],oldc[ci[0]+4]};
5737 pt=std::copy(tmp,tmp+8,pt);
5746 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5747 ptI[1]=ptI[0]+ci[1]-ci[0];
5752 _nodal_connec->decrRef();
5753 _nodal_connec=newConn.retn();
5754 _nodal_connec_index->decrRef();
5755 _nodal_connec_index=newConnI.retn();
5762 * This method implements policy INTERP_KERNEL::PLANAR_FACE_5 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5764 DataArrayInt *MEDCouplingUMesh::simplexizePlanarFace5()
5766 checkConnectivityFullyDefined();
5767 if(getMeshDimension()!=3)
5768 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePlanarFace5 : this policy is only available for mesh with meshdim == 3 !");
5769 int nbOfCells=getNumberOfCells();
5770 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5771 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_HEXA8);
5772 ret->alloc(nbOfCells+4*nbOfCutCells,1);
5773 if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5774 int *retPt=ret->getPointer();
5775 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5776 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5777 newConnI->alloc(nbOfCells+4*nbOfCutCells+1,1);
5778 newConn->alloc(getNodalConnectivityArrayLen()+16*nbOfCutCells,1);//21
5779 int *pt=newConn->getPointer();
5780 int *ptI=newConnI->getPointer();
5782 const int *oldc=_nodal_connec->getConstPointer();
5783 const int *ci=_nodal_connec_index->getConstPointer();
5784 for(int i=0;i<nbOfCells;i++,ci++)
5786 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_HEXA8)
5788 for(int j=0;j<5;j++,pt+=5,ptI++)
5790 pt[0]=(int)INTERP_KERNEL::NORM_TETRA4;
5791 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];
5798 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5799 ptI[1]=ptI[0]+ci[1]-ci[0];
5804 _nodal_connec->decrRef();
5805 _nodal_connec=newConn.retn();
5806 _nodal_connec_index->decrRef();
5807 _nodal_connec_index=newConnI.retn();
5814 * This method implements policy INTERP_KERNEL::PLANAR_FACE_6 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5816 DataArrayInt *MEDCouplingUMesh::simplexizePlanarFace6()
5818 checkConnectivityFullyDefined();
5819 if(getMeshDimension()!=3)
5820 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePlanarFace6 : this policy is only available for mesh with meshdim == 3 !");
5821 int nbOfCells=getNumberOfCells();
5822 MCAuto<DataArrayInt> ret=DataArrayInt::New();
5823 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_HEXA8);
5824 ret->alloc(nbOfCells+5*nbOfCutCells,1);
5825 if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5826 int *retPt=ret->getPointer();
5827 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5828 MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5829 newConnI->alloc(nbOfCells+5*nbOfCutCells+1,1);
5830 newConn->alloc(getNodalConnectivityArrayLen()+21*nbOfCutCells,1);
5831 int *pt=newConn->getPointer();
5832 int *ptI=newConnI->getPointer();
5834 const int *oldc=_nodal_connec->getConstPointer();
5835 const int *ci=_nodal_connec_index->getConstPointer();
5836 for(int i=0;i<nbOfCells;i++,ci++)
5838 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_HEXA8)
5840 for(int j=0;j<6;j++,pt+=5,ptI++)
5842 pt[0]=(int)INTERP_KERNEL::NORM_TETRA4;
5843 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];
5850 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5851 ptI[1]=ptI[0]+ci[1]-ci[0];
5856 _nodal_connec->decrRef();
5857 _nodal_connec=newConn.retn();
5858 _nodal_connec_index->decrRef();
5859 _nodal_connec_index=newConnI.retn();
5866 * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
5867 * so that the number of cells remains the same. Quadratic faces are converted to
5868 * polygons. This method works only for 2D meshes in
5869 * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
5870 * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
5871 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5872 * \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
5873 * a polylinized edge constituting the input polygon.
5874 * \throw If the coordinates array is not set.
5875 * \throw If the nodal connectivity of cells is not defined.
5876 * \throw If \a this->getMeshDimension() != 2.
5877 * \throw If \a this->getSpaceDimension() != 2.
5879 void MEDCouplingUMesh::tessellate2DInternal(double eps)
5881 checkFullyDefined();
5882 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
5883 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DInternal works on umeshes with meshdim equal to 2 and spaceDim equal to 2 too!");
5884 double epsa=fabs(eps);
5885 if(epsa<std::numeric_limits<double>::min())
5886 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 !");
5887 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
5888 MCAuto<MEDCouplingUMesh> mDesc(buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1));
5889 revDesc1=0; revDescIndx1=0;
5890 mDesc->tessellate2D(eps);
5891 subDivide2DMesh(mDesc->_nodal_connec->getConstPointer(),mDesc->_nodal_connec_index->getConstPointer(),desc1->getConstPointer(),descIndx1->getConstPointer());
5892 setCoords(mDesc->getCoords());
5896 * Tessellates \a this 1D mesh in 2D space by dividing not straight quadratic edges.
5897 * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5898 * \param [in] eps - specifies the maximal angle (in radian) between 2 sub-edges of
5899 * a sub-divided edge.
5900 * \throw If the coordinates array is not set.
5901 * \throw If the nodal connectivity of cells is not defined.
5902 * \throw If \a this->getMeshDimension() != 1.
5903 * \throw If \a this->getSpaceDimension() != 2.
5905 void MEDCouplingUMesh::tessellate2DCurveInternal(double eps)
5907 checkFullyDefined();
5908 if(getMeshDimension()!=1 || getSpaceDimension()!=2)
5909 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DCurveInternal works on umeshes with meshdim equal to 1 and spaceDim equal to 2 too!");
5910 double epsa=fabs(eps);
5911 if(epsa<std::numeric_limits<double>::min())
5912 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 !");
5913 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=1.e-10;
5914 int nbCells=getNumberOfCells();
5915 int nbNodes=getNumberOfNodes();
5916 const int *conn=_nodal_connec->getConstPointer();
5917 const int *connI=_nodal_connec_index->getConstPointer();
5918 const double *coords=_coords->getConstPointer();
5919 std::vector<double> addCoo;
5920 std::vector<int> newConn;//no direct DataArrayInt because interface with Geometric2D
5921 MCAuto<DataArrayInt> newConnI(DataArrayInt::New());
5922 newConnI->alloc(nbCells+1,1);
5923 int *newConnIPtr=newConnI->getPointer();
5926 INTERP_KERNEL::Node *tmp2[3];
5927 std::set<INTERP_KERNEL::NormalizedCellType> types;
5928 for(int i=0;i<nbCells;i++,newConnIPtr++)
5930 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5931 if(cm.isQuadratic())
5932 {//assert(connI[i+1]-connI[i]-1==3)
5933 tmp1[0]=conn[connI[i]+1+0]; tmp1[1]=conn[connI[i]+1+1]; tmp1[2]=conn[connI[i]+1+2];
5934 tmp2[0]=new INTERP_KERNEL::Node(coords[2*tmp1[0]],coords[2*tmp1[0]+1]);
5935 tmp2[1]=new INTERP_KERNEL::Node(coords[2*tmp1[1]],coords[2*tmp1[1]+1]);
5936 tmp2[2]=new INTERP_KERNEL::Node(coords[2*tmp1[2]],coords[2*tmp1[2]+1]);
5937 INTERP_KERNEL::EdgeArcCircle *eac=INTERP_KERNEL::EdgeArcCircle::BuildFromNodes(tmp2[0],tmp2[2],tmp2[1]);
5940 eac->tesselate(tmp1,nbNodes,epsa,newConn,addCoo);
5941 types.insert((INTERP_KERNEL::NormalizedCellType)newConn[newConnIPtr[0]]);
5943 newConnIPtr[1]=(int)newConn.size();
5947 types.insert(INTERP_KERNEL::NORM_SEG2);
5948 newConn.push_back(INTERP_KERNEL::NORM_SEG2);
5949 newConn.insert(newConn.end(),conn+connI[i]+1,conn+connI[i]+3);
5950 newConnIPtr[1]=newConnIPtr[0]+3;
5955 types.insert((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5956 newConn.insert(newConn.end(),conn+connI[i],conn+connI[i+1]);
5957 newConnIPtr[1]=newConnIPtr[0]+3;
5960 if(addCoo.empty() && ((int)newConn.size())==_nodal_connec->getNumberOfTuples())//nothing happens during tessellation : no update needed
5963 DataArrayInt::SetArrayIn(newConnI,_nodal_connec_index);
5964 MCAuto<DataArrayInt> newConnArr=DataArrayInt::New();
5965 newConnArr->alloc((int)newConn.size(),1);
5966 std::copy(newConn.begin(),newConn.end(),newConnArr->getPointer());
5967 DataArrayInt::SetArrayIn(newConnArr,_nodal_connec);
5968 MCAuto<DataArrayDouble> newCoords=DataArrayDouble::New();
5969 newCoords->alloc(nbNodes+((int)addCoo.size())/2,2);
5970 double *work=std::copy(_coords->begin(),_coords->end(),newCoords->getPointer());
5971 std::copy(addCoo.begin(),addCoo.end(),work);
5972 DataArrayDouble::SetArrayIn(newCoords,_coords);
5977 * 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.
5978 * This method completly ignore coordinates.
5979 * \param nodeSubdived is the nodal connectivity of subdivision of edges
5980 * \param nodeIndxSubdived is the nodal connectivity index of subdivision of edges
5981 * \param desc is descending connectivity in format specified in MEDCouplingUMesh::buildDescendingConnectivity2
5982 * \param descIndex is descending connectivity index in format specified in MEDCouplingUMesh::buildDescendingConnectivity2
5984 void MEDCouplingUMesh::subDivide2DMesh(const int *nodeSubdived, const int *nodeIndxSubdived, const int *desc, const int *descIndex)
5986 checkFullyDefined();
5987 if(getMeshDimension()!=2)
5988 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::subDivide2DMesh : works only on umesh with meshdim==2 !");
5989 int nbOfCells=getNumberOfCells();
5990 int *connI=_nodal_connec_index->getPointer();
5992 for(int i=0;i<nbOfCells;i++,connI++)
5994 int offset=descIndex[i];
5995 int nbOfEdges=descIndex[i+1]-offset;
5997 bool ddirect=desc[offset+nbOfEdges-1]>0;
5998 int eedgeId=std::abs(desc[offset+nbOfEdges-1])-1;
5999 int ref=ddirect?nodeSubdived[nodeIndxSubdived[eedgeId+1]-1]:nodeSubdived[nodeIndxSubdived[eedgeId]+1];
6000 for(int j=0;j<nbOfEdges;j++)
6002 bool direct=desc[offset+j]>0;
6003 int edgeId=std::abs(desc[offset+j])-1;
6004 if(!INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodeSubdived[nodeIndxSubdived[edgeId]]).isQuadratic())
6006 int id1=nodeSubdived[nodeIndxSubdived[edgeId]+1];
6007 int id2=nodeSubdived[nodeIndxSubdived[edgeId+1]-1];
6008 int ref2=direct?id1:id2;
6011 int nbOfSubNodes=nodeIndxSubdived[edgeId+1]-nodeIndxSubdived[edgeId]-1;
6012 newConnLgth+=nbOfSubNodes-1;
6017 std::ostringstream oss; oss << "MEDCouplingUMesh::subDivide2DMesh : On polygon #" << i << " edgeid #" << j << " subedges mismatch : end subedge k!=start subedge k+1 !";
6018 throw INTERP_KERNEL::Exception(oss.str());
6023 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::subDivide2DMesh : this method only subdivides into linear edges !");
6026 newConnLgth++;//+1 is for cell type
6027 connI[1]=newConnLgth;
6030 MCAuto<DataArrayInt> newConn=DataArrayInt::New();
6031 newConn->alloc(newConnLgth,1);
6032 int *work=newConn->getPointer();
6033 for(int i=0;i<nbOfCells;i++)
6035 *work++=INTERP_KERNEL::NORM_POLYGON;
6036 int offset=descIndex[i];
6037 int nbOfEdges=descIndex[i+1]-offset;
6038 for(int j=0;j<nbOfEdges;j++)
6040 bool direct=desc[offset+j]>0;
6041 int edgeId=std::abs(desc[offset+j])-1;
6043 work=std::copy(nodeSubdived+nodeIndxSubdived[edgeId]+1,nodeSubdived+nodeIndxSubdived[edgeId+1]-1,work);
6046 int nbOfSubNodes=nodeIndxSubdived[edgeId+1]-nodeIndxSubdived[edgeId]-1;
6047 std::reverse_iterator<const int *> it(nodeSubdived+nodeIndxSubdived[edgeId+1]);
6048 work=std::copy(it,it+nbOfSubNodes-1,work);
6052 DataArrayInt::SetArrayIn(newConn,_nodal_connec);
6055 _types.insert(INTERP_KERNEL::NORM_POLYGON);
6059 * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
6060 * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
6061 * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell. This method
6062 * does \b not perform geometrical checks and checks only nodal connectivity of cells,
6063 * so it can be useful to call mergeNodes() before calling this method.
6064 * \throw If \a this->getMeshDimension() <= 1.
6065 * \throw If the coordinates array is not set.
6066 * \throw If the nodal connectivity of cells is not defined.
6068 void MEDCouplingUMesh::convertDegeneratedCells()
6070 checkFullyDefined();
6071 if(getMeshDimension()<=1)
6072 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
6073 int nbOfCells=getNumberOfCells();
6076 int initMeshLgth=getNodalConnectivityArrayLen();
6077 int *conn=_nodal_connec->getPointer();
6078 int *index=_nodal_connec_index->getPointer();
6082 for(int i=0;i<nbOfCells;i++)
6084 lgthOfCurCell=index[i+1]-posOfCurCell;
6085 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
6087 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
6088 conn+newPos+1,newLgth);
6089 conn[newPos]=newType;
6091 posOfCurCell=index[i+1];
6094 if(newPos!=initMeshLgth)
6095 _nodal_connec->reAlloc(newPos);
6100 * Finds incorrectly oriented cells of this 2D mesh in 3D space.
6101 * A cell is considered to be oriented correctly if an angle between its
6102 * normal vector and a given vector is less than \c PI / \c 2.
6103 * \param [in] vec - 3 components of the vector specifying the correct orientation of
6105 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
6107 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
6108 * is not cleared before filling in.
6109 * \throw If \a this->getMeshDimension() != 2.
6110 * \throw If \a this->getSpaceDimension() != 3.
6112 * \if ENABLE_EXAMPLES
6113 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
6114 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
6117 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<int>& cells) const
6119 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6120 throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
6121 int nbOfCells=getNumberOfCells();
6122 const int *conn=_nodal_connec->getConstPointer();
6123 const int *connI=_nodal_connec_index->getConstPointer();
6124 const double *coordsPtr=_coords->getConstPointer();
6125 for(int i=0;i<nbOfCells;i++)
6127 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6128 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
6130 bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
6131 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6138 * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
6139 * considered to be oriented correctly if an angle between its normal vector and a
6140 * given vector is less than \c PI / \c 2.
6141 * \param [in] vec - 3 components of the vector specifying the correct orientation of
6143 * \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
6145 * \throw If \a this->getMeshDimension() != 2.
6146 * \throw If \a this->getSpaceDimension() != 3.
6148 * \if ENABLE_EXAMPLES
6149 * \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
6150 * \ref py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
6153 * \sa changeOrientationOfCells
6155 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
6157 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6158 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
6159 int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
6160 const int *connI(_nodal_connec_index->getConstPointer());
6161 const double *coordsPtr(_coords->getConstPointer());
6162 bool isModified(false);
6163 for(int i=0;i<nbOfCells;i++)
6165 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6166 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
6168 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6169 bool isQuadratic(cm.isQuadratic());
6170 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6173 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6178 _nodal_connec->declareAsNew();
6183 * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
6185 * \sa orientCorrectly2DCells
6187 void MEDCouplingUMesh::changeOrientationOfCells()
6189 int mdim(getMeshDimension());
6190 if(mdim!=2 && mdim!=1)
6191 throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
6192 int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
6193 const int *connI(_nodal_connec_index->getConstPointer());
6196 for(int i=0;i<nbOfCells;i++)
6198 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6199 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6200 cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6205 for(int i=0;i<nbOfCells;i++)
6207 INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6208 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6209 cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6215 * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
6216 * oriented facets. The normal vector of the facet should point out of the cell.
6217 * \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
6218 * is not cleared before filling in.
6219 * \throw If \a this->getMeshDimension() != 3.
6220 * \throw If \a this->getSpaceDimension() != 3.
6221 * \throw If the coordinates array is not set.
6222 * \throw If the nodal connectivity of cells is not defined.
6224 * \if ENABLE_EXAMPLES
6225 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
6226 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
6229 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<int>& cells) const
6231 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6232 throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
6233 int nbOfCells=getNumberOfCells();
6234 const int *conn=_nodal_connec->getConstPointer();
6235 const int *connI=_nodal_connec_index->getConstPointer();
6236 const double *coordsPtr=_coords->getConstPointer();
6237 for(int i=0;i<nbOfCells;i++)
6239 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6240 if(type==INTERP_KERNEL::NORM_POLYHED)
6242 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6249 * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
6251 * \throw If \a this->getMeshDimension() != 3.
6252 * \throw If \a this->getSpaceDimension() != 3.
6253 * \throw If the coordinates array is not set.
6254 * \throw If the nodal connectivity of cells is not defined.
6255 * \throw If the reparation fails.
6257 * \if ENABLE_EXAMPLES
6258 * \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
6259 * \ref py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
6261 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
6263 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
6265 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6266 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
6267 int nbOfCells=getNumberOfCells();
6268 int *conn=_nodal_connec->getPointer();
6269 const int *connI=_nodal_connec_index->getConstPointer();
6270 const double *coordsPtr=_coords->getConstPointer();
6271 for(int i=0;i<nbOfCells;i++)
6273 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6274 if(type==INTERP_KERNEL::NORM_POLYHED)
6278 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6279 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
6281 catch(INTERP_KERNEL::Exception& e)
6283 std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
6284 throw INTERP_KERNEL::Exception(oss.str());
6292 * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
6293 * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
6294 * according to which the first facet of the cell should be oriented to have the normal vector
6295 * pointing out of cell.
6296 * \return DataArrayInt * - a new instance of DataArrayInt holding ids of fixed
6297 * cells. The caller is to delete this array using decrRef() as it is no more
6299 * \throw If \a this->getMeshDimension() != 3.
6300 * \throw If \a this->getSpaceDimension() != 3.
6301 * \throw If the coordinates array is not set.
6302 * \throw If the nodal connectivity of cells is not defined.
6304 * \if ENABLE_EXAMPLES
6305 * \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
6306 * \ref py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
6308 * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
6310 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
6312 const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
6313 if(getMeshDimension()!=3)
6314 throw INTERP_KERNEL::Exception(msg);
6315 int spaceDim=getSpaceDimension();
6317 throw INTERP_KERNEL::Exception(msg);
6319 int nbOfCells=getNumberOfCells();
6320 int *conn=_nodal_connec->getPointer();
6321 const int *connI=_nodal_connec_index->getConstPointer();
6322 const double *coo=getCoords()->getConstPointer();
6323 MCAuto<DataArrayInt> cells(DataArrayInt::New()); cells->alloc(0,1);
6324 for(int i=0;i<nbOfCells;i++)
6326 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6327 if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
6329 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
6331 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
6332 cells->pushBackSilent(i);
6336 return cells.retn();
6340 * This method is a faster method to correct orientation of all 3D cells in \a this.
6341 * 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.
6342 * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
6344 * \return a newly allocated int array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
6345 * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
6347 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
6349 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6350 throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
6351 int nbOfCells=getNumberOfCells();
6352 int *conn=_nodal_connec->getPointer();
6353 const int *connI=_nodal_connec_index->getConstPointer();
6354 const double *coordsPtr=_coords->getConstPointer();
6355 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
6356 for(int i=0;i<nbOfCells;i++)
6358 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6361 case INTERP_KERNEL::NORM_TETRA4:
6363 if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6365 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
6366 ret->pushBackSilent(i);
6370 case INTERP_KERNEL::NORM_PYRA5:
6372 if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6374 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
6375 ret->pushBackSilent(i);
6379 case INTERP_KERNEL::NORM_PENTA6:
6380 case INTERP_KERNEL::NORM_HEXA8:
6381 case INTERP_KERNEL::NORM_HEXGP12:
6383 if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6385 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
6386 ret->pushBackSilent(i);
6390 case INTERP_KERNEL::NORM_POLYHED:
6392 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6394 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
6395 ret->pushBackSilent(i);
6400 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 !");
6408 * This method has a sense for meshes with spaceDim==3 and meshDim==2.
6409 * If it is not the case an exception will be thrown.
6410 * This method is fast because the first cell of \a this is used to compute the plane.
6411 * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
6412 * \param pos output of size at least 3 used to store a point owned of searched plane.
6414 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
6416 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6417 throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
6418 const int *conn=_nodal_connec->getConstPointer();
6419 const int *connI=_nodal_connec_index->getConstPointer();
6420 const double *coordsPtr=_coords->getConstPointer();
6421 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
6422 std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
6426 * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
6427 * cells. Currently cells of the following types are treated:
6428 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
6429 * For a cell of other type an exception is thrown.
6430 * Space dimension of a 2D mesh can be either 2 or 3.
6431 * The Edge Ratio of a cell \f$t\f$ is:
6432 * \f$\frac{|t|_\infty}{|t|_0}\f$,
6433 * where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
6434 * the smallest edge lengths of \f$t\f$.
6435 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6436 * cells and one time, lying on \a this mesh. The caller is to delete this
6437 * field using decrRef() as it is no more needed.
6438 * \throw If the coordinates array is not set.
6439 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6440 * \throw If the connectivity data array has more than one component.
6441 * \throw If the connectivity data array has a named component.
6442 * \throw If the connectivity index data array has more than one component.
6443 * \throw If the connectivity index data array has a named component.
6444 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
6445 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
6446 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
6448 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
6450 checkConsistencyLight();
6451 int spaceDim=getSpaceDimension();
6452 int meshDim=getMeshDimension();
6453 if(spaceDim!=2 && spaceDim!=3)
6454 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
6455 if(meshDim!=2 && meshDim!=3)
6456 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
6457 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6459 int nbOfCells=getNumberOfCells();
6460 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6461 arr->alloc(nbOfCells,1);
6462 double *pt=arr->getPointer();
6463 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6464 const int *conn=_nodal_connec->getConstPointer();
6465 const int *connI=_nodal_connec_index->getConstPointer();
6466 const double *coo=_coords->getConstPointer();
6468 for(int i=0;i<nbOfCells;i++,pt++)
6470 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6473 case INTERP_KERNEL::NORM_TRI3:
6475 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
6476 *pt=INTERP_KERNEL::triEdgeRatio(tmp);
6479 case INTERP_KERNEL::NORM_QUAD4:
6481 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6482 *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
6485 case INTERP_KERNEL::NORM_TETRA4:
6487 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6488 *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
6492 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
6494 conn+=connI[i+1]-connI[i];
6496 ret->setName("EdgeRatio");
6497 ret->synchronizeTimeWithSupport();
6502 * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
6503 * cells. Currently cells of the following types are treated:
6504 * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
6505 * For a cell of other type an exception is thrown.
6506 * Space dimension of a 2D mesh can be either 2 or 3.
6507 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6508 * cells and one time, lying on \a this mesh. The caller is to delete this
6509 * field using decrRef() as it is no more needed.
6510 * \throw If the coordinates array is not set.
6511 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6512 * \throw If the connectivity data array has more than one component.
6513 * \throw If the connectivity data array has a named component.
6514 * \throw If the connectivity index data array has more than one component.
6515 * \throw If the connectivity index data array has a named component.
6516 * \throw If \a this->getMeshDimension() is neither 2 nor 3.
6517 * \throw If \a this->getSpaceDimension() is neither 2 nor 3.
6518 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
6520 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
6522 checkConsistencyLight();
6523 int spaceDim=getSpaceDimension();
6524 int meshDim=getMeshDimension();
6525 if(spaceDim!=2 && spaceDim!=3)
6526 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
6527 if(meshDim!=2 && meshDim!=3)
6528 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
6529 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6531 int nbOfCells=getNumberOfCells();
6532 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6533 arr->alloc(nbOfCells,1);
6534 double *pt=arr->getPointer();
6535 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6536 const int *conn=_nodal_connec->getConstPointer();
6537 const int *connI=_nodal_connec_index->getConstPointer();
6538 const double *coo=_coords->getConstPointer();
6540 for(int i=0;i<nbOfCells;i++,pt++)
6542 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6545 case INTERP_KERNEL::NORM_TRI3:
6547 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
6548 *pt=INTERP_KERNEL::triAspectRatio(tmp);
6551 case INTERP_KERNEL::NORM_QUAD4:
6553 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6554 *pt=INTERP_KERNEL::quadAspectRatio(tmp);
6557 case INTERP_KERNEL::NORM_TETRA4:
6559 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6560 *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
6564 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
6566 conn+=connI[i+1]-connI[i];
6568 ret->setName("AspectRatio");
6569 ret->synchronizeTimeWithSupport();
6574 * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
6575 * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
6576 * in 3D space. Currently only cells of the following types are
6577 * treated: INTERP_KERNEL::NORM_QUAD4.
6578 * For a cell of other type an exception is thrown.
6579 * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
6581 * \f$t=\vec{da}\times\vec{ab}\f$,
6582 * \f$u=\vec{ab}\times\vec{bc}\f$
6583 * \f$v=\vec{bc}\times\vec{cd}\f$
6584 * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
6586 * W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
6588 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6589 * cells and one time, lying on \a this mesh. The caller is to delete this
6590 * field using decrRef() as it is no more needed.
6591 * \throw If the coordinates array is not set.
6592 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6593 * \throw If the connectivity data array has more than one component.
6594 * \throw If the connectivity data array has a named component.
6595 * \throw If the connectivity index data array has more than one component.
6596 * \throw If the connectivity index data array has a named component.
6597 * \throw If \a this->getMeshDimension() != 2.
6598 * \throw If \a this->getSpaceDimension() != 3.
6599 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
6601 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
6603 checkConsistencyLight();
6604 int spaceDim=getSpaceDimension();
6605 int meshDim=getMeshDimension();
6607 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
6609 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
6610 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6612 int nbOfCells=getNumberOfCells();
6613 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6614 arr->alloc(nbOfCells,1);
6615 double *pt=arr->getPointer();
6616 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6617 const int *conn=_nodal_connec->getConstPointer();
6618 const int *connI=_nodal_connec_index->getConstPointer();
6619 const double *coo=_coords->getConstPointer();
6621 for(int i=0;i<nbOfCells;i++,pt++)
6623 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6626 case INTERP_KERNEL::NORM_QUAD4:
6628 FillInCompact3DMode(3,4,conn+1,coo,tmp);
6629 *pt=INTERP_KERNEL::quadWarp(tmp);
6633 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
6635 conn+=connI[i+1]-connI[i];
6637 ret->setName("Warp");
6638 ret->synchronizeTimeWithSupport();
6644 * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
6645 * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
6646 * treated: INTERP_KERNEL::NORM_QUAD4.
6647 * The skew is computed as follow for a quad with points (a,b,c,d): let
6648 * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
6649 * then the skew is computed as:
6651 * s=\frac{u}{|u|}\cdot\frac{v}{|v|}
6654 * For a cell of other type an exception is thrown.
6655 * \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6656 * cells and one time, lying on \a this mesh. The caller is to delete this
6657 * field using decrRef() as it is no more needed.
6658 * \throw If the coordinates array is not set.
6659 * \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6660 * \throw If the connectivity data array has more than one component.
6661 * \throw If the connectivity data array has a named component.
6662 * \throw If the connectivity index data array has more than one component.
6663 * \throw If the connectivity index data array has a named component.
6664 * \throw If \a this->getMeshDimension() != 2.
6665 * \throw If \a this->getSpaceDimension() != 3.
6666 * \throw If \a this mesh includes cells of type different from the ones enumerated above.
6668 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
6670 checkConsistencyLight();
6671 int spaceDim=getSpaceDimension();
6672 int meshDim=getMeshDimension();
6674 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
6676 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
6677 MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6679 int nbOfCells=getNumberOfCells();
6680 MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6681 arr->alloc(nbOfCells,1);
6682 double *pt=arr->getPointer();
6683 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6684 const int *conn=_nodal_connec->getConstPointer();
6685 const int *connI=_nodal_connec_index->getConstPointer();
6686 const double *coo=_coords->getConstPointer();
6688 for(int i=0;i<nbOfCells;i++,pt++)
6690 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6693 case INTERP_KERNEL::NORM_QUAD4:
6695 FillInCompact3DMode(3,4,conn+1,coo,tmp);
6696 *pt=INTERP_KERNEL::quadSkew(tmp);
6700 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
6702 conn+=connI[i+1]-connI[i];
6704 ret->setName("Skew");
6705 ret->synchronizeTimeWithSupport();
6710 * 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.
6712 * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
6714 * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
6716 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
6718 checkConsistencyLight();
6719 MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
6721 std::set<INTERP_KERNEL::NormalizedCellType> types;
6722 ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
6723 int spaceDim(getSpaceDimension()),nbCells(getNumberOfCells());
6724 MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6725 arr->alloc(nbCells,1);
6726 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
6728 INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
6729 MCAuto<DataArrayInt> cellIds(giveCellsWithType(*it));
6730 dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
6733 ret->setName("Diameter");
6738 * This method aggregate the bbox of each cell and put it into bbox parameter (xmin,xmax,ymin,ymax,zmin,zmax).
6740 * \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)
6741 * For all other cases this input parameter is ignored.
6742 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6744 * \throw If \a this is not fully set (coordinates and connectivity).
6745 * \throw If a cell in \a this has no valid nodeId.
6746 * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
6748 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
6750 int mDim(getMeshDimension()),sDim(getSpaceDimension());
6751 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.
6752 return getBoundingBoxForBBTreeFast();
6753 if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
6755 bool presenceOfQuadratic(false);
6756 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
6758 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
6759 if(cm.isQuadratic())
6760 presenceOfQuadratic=true;
6762 if(!presenceOfQuadratic)
6763 return getBoundingBoxForBBTreeFast();
6764 if(mDim==2 && sDim==2)
6765 return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
6767 return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
6769 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) !");
6773 * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
6774 * So meshes having quadratic cells the computed bounding boxes can be invalid !
6776 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6778 * \throw If \a this is not fully set (coordinates and connectivity).
6779 * \throw If a cell in \a this has no valid nodeId.
6781 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
6783 checkFullyDefined();
6784 int spaceDim(getSpaceDimension()),nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
6785 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6786 double *bbox(ret->getPointer());
6787 for(int i=0;i<nbOfCells*spaceDim;i++)
6789 bbox[2*i]=std::numeric_limits<double>::max();
6790 bbox[2*i+1]=-std::numeric_limits<double>::max();
6792 const double *coordsPtr(_coords->getConstPointer());
6793 const int *conn(_nodal_connec->getConstPointer()),*connI(_nodal_connec_index->getConstPointer());
6794 for(int i=0;i<nbOfCells;i++)
6796 int offset=connI[i]+1;
6797 int nbOfNodesForCell(connI[i+1]-offset),kk(0);
6798 for(int j=0;j<nbOfNodesForCell;j++)
6800 int nodeId=conn[offset+j];
6801 if(nodeId>=0 && nodeId<nbOfNodes)
6803 for(int k=0;k<spaceDim;k++)
6805 bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
6806 bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
6813 std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
6814 throw INTERP_KERNEL::Exception(oss.str());
6821 * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
6822 * useful for 2D meshes having quadratic cells
6823 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
6824 * the two extremities of the arc of circle).
6826 * \param [in] arcDetEps - a parameter specifying in case of 2D quadratic polygon cell the detection limit between linear and arc circle. (By default 1e-12)
6827 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6828 * \throw If \a this is not fully defined.
6829 * \throw If \a this is not a mesh with meshDimension equal to 2.
6830 * \throw If \a this is not a mesh with spaceDimension equal to 2.
6831 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
6833 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
6835 checkFullyDefined();
6836 int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
6837 if(spaceDim!=2 || mDim!=2)
6838 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!");
6839 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6840 double *bbox(ret->getPointer());
6841 const double *coords(_coords->getConstPointer());
6842 const int *conn(_nodal_connec->getConstPointer()),*connI(_nodal_connec_index->getConstPointer());
6843 for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
6845 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
6846 int sz(connI[1]-connI[0]-1);
6847 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=arcDetEps;
6848 std::vector<INTERP_KERNEL::Node *> nodes(sz);
6849 INTERP_KERNEL::QuadraticPolygon *pol(0);
6850 for(int j=0;j<sz;j++)
6852 int nodeId(conn[*connI+1+j]);
6853 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
6855 if(!cm.isQuadratic())
6856 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
6858 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
6859 INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
6860 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
6866 * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
6867 * useful for 2D meshes having quadratic cells
6868 * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
6869 * the two extremities of the arc of circle).
6871 * \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)
6872 * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6873 * \throw If \a this is not fully defined.
6874 * \throw If \a this is not a mesh with meshDimension equal to 1.
6875 * \throw If \a this is not a mesh with spaceDimension equal to 2.
6876 * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
6878 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
6880 checkFullyDefined();
6881 int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
6882 if(spaceDim!=2 || mDim!=1)
6883 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!");
6884 MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6885 double *bbox(ret->getPointer());
6886 const double *coords(_coords->getConstPointer());
6887 const int *conn(_nodal_connec->getConstPointer()),*connI(_nodal_connec_index->getConstPointer());
6888 for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
6890 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
6891 int sz(connI[1]-connI[0]-1);
6892 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=arcDetEps;
6893 std::vector<INTERP_KERNEL::Node *> nodes(sz);
6894 INTERP_KERNEL::Edge *edge(0);
6895 for(int j=0;j<sz;j++)
6897 int nodeId(conn[*connI+1+j]);
6898 nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
6900 if(!cm.isQuadratic())
6901 edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
6903 edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
6904 const INTERP_KERNEL::Bounds& b(edge->getBounds());
6905 bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
6912 namespace MEDCouplingImpl
6917 ConnReader(const int *c, int val):_conn(c),_val(val) { }
6918 bool operator() (const int& pos) { return _conn[pos]!=_val; }
6927 ConnReader2(const int *c, int val):_conn(c),_val(val) { }
6928 bool operator() (const int& pos) { return _conn[pos]==_val; }
6938 * This method expects that \a this is sorted by types. If not an exception will be thrown.
6939 * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
6940 * \a this is composed in cell types.
6941 * The returned array is of size 3*n where n is the number of different types present in \a this.
6942 * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
6943 * This parameter is kept only for compatibility with other methode listed above.
6945 std::vector<int> MEDCouplingUMesh::getDistributionOfTypes() const
6947 checkConnectivityFullyDefined();
6948 const int *conn=_nodal_connec->getConstPointer();
6949 const int *connI=_nodal_connec_index->getConstPointer();
6950 const int *work=connI;
6951 int nbOfCells=getNumberOfCells();
6952 std::size_t n=getAllGeoTypes().size();
6953 std::vector<int> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
6954 std::set<INTERP_KERNEL::NormalizedCellType> types;
6955 for(std::size_t i=0;work!=connI+nbOfCells;i++)
6957 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
6958 if(types.find(typ)!=types.end())
6960 std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
6961 oss << " is not contiguous !";
6962 throw INTERP_KERNEL::Exception(oss.str());
6966 const int *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
6967 ret[3*i+1]=(int)std::distance(work,work2);
6974 * This method is used to check that this has contiguous cell type in same order than described in \a code.
6975 * only for types cell, type node is not managed.
6976 * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
6977 * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
6978 * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
6979 * If 2 or more same geometric type is in \a code and exception is thrown too.
6981 * This method firstly checks
6982 * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
6983 * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
6984 * an exception is thrown too.
6986 * If all geometric types in \a code are exactly those in \a this null pointer is returned.
6987 * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
6988 * and a DataArrayInt instance is returned that the user has the responsability to deallocate.
6990 DataArrayInt *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<int>& code, const std::vector<const DataArrayInt *>& idsPerType) const
6993 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
6994 std::size_t sz=code.size();
6997 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
6998 std::vector<INTERP_KERNEL::NormalizedCellType> types;
7000 bool isNoPflUsed=true;
7001 for(std::size_t i=0;i<n;i++)
7002 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
7004 types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
7006 if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
7007 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
7008 isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
7011 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
7014 if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
7015 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
7016 if(types.size()==_types.size())
7019 MCAuto<DataArrayInt> ret=DataArrayInt::New();
7021 int *retPtr=ret->getPointer();
7022 const int *connI=_nodal_connec_index->getConstPointer();
7023 const int *conn=_nodal_connec->getConstPointer();
7024 int nbOfCells=getNumberOfCells();
7027 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
7029 i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,(int)(*it)));
7030 int offset=(int)std::distance(connI,i);
7031 const int *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)(*it)));
7032 int nbOfCellsOfCurType=(int)std::distance(i,j);
7033 if(code[3*kk+2]==-1)
7034 for(int k=0;k<nbOfCellsOfCurType;k++)
7038 int idInIdsPerType=code[3*kk+2];
7039 if(idInIdsPerType>=0 && idInIdsPerType<(int)idsPerType.size())
7041 const DataArrayInt *zePfl=idsPerType[idInIdsPerType];
7044 zePfl->checkAllocated();
7045 if(zePfl->getNumberOfComponents()==1)
7047 for(const int *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
7049 if(*k>=0 && *k<nbOfCellsOfCurType)
7050 *retPtr=(*k)+offset;
7053 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
7054 oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
7055 throw INTERP_KERNEL::Exception(oss.str());
7060 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
7063 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
7067 std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
7068 oss << " should be in [0," << idsPerType.size() << ") !";
7069 throw INTERP_KERNEL::Exception(oss.str());
7078 * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
7079 * 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.
7080 * 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.
7081 * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
7083 * \param [in] profile
7084 * \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.
7085 * \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,
7086 * \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
7087 * \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.
7088 * This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
7089 * \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
7091 void MEDCouplingUMesh::splitProfilePerType(const DataArrayInt *profile, std::vector<int>& code, std::vector<DataArrayInt *>& idsInPflPerType, std::vector<DataArrayInt *>& idsPerType) const
7094 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
7095 if(profile->getNumberOfComponents()!=1)
7096 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
7097 checkConnectivityFullyDefined();
7098 const int *conn=_nodal_connec->getConstPointer();
7099 const int *connI=_nodal_connec_index->getConstPointer();
7100 int nbOfCells=getNumberOfCells();
7101 std::vector<INTERP_KERNEL::NormalizedCellType> types;
7102 std::vector<int> typeRangeVals(1);
7103 for(const int *i=connI;i!=connI+nbOfCells;)
7105 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7106 if(std::find(types.begin(),types.end(),curType)!=types.end())
7108 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
7110 types.push_back(curType);
7111 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7112 typeRangeVals.push_back((int)std::distance(connI,i));
7115 DataArrayInt *castArr=0,*rankInsideCast=0,*castsPresent=0;
7116 profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
7117 MCAuto<DataArrayInt> tmp0=castArr;
7118 MCAuto<DataArrayInt> tmp1=rankInsideCast;
7119 MCAuto<DataArrayInt> tmp2=castsPresent;
7121 int nbOfCastsFinal=castsPresent->getNumberOfTuples();
7122 code.resize(3*nbOfCastsFinal);
7123 std::vector< MCAuto<DataArrayInt> > idsInPflPerType2;
7124 std::vector< MCAuto<DataArrayInt> > idsPerType2;
7125 for(int i=0;i<nbOfCastsFinal;i++)
7127 int castId=castsPresent->getIJ(i,0);
7128 MCAuto<DataArrayInt> tmp3=castArr->findIdsEqual(castId);
7129 idsInPflPerType2.push_back(tmp3);
7130 code[3*i]=(int)types[castId];
7131 code[3*i+1]=tmp3->getNumberOfTuples();
7132 MCAuto<DataArrayInt> tmp4=rankInsideCast->selectByTupleId(tmp3->getConstPointer(),tmp3->getConstPointer()+tmp3->getNumberOfTuples());
7133 if(!tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
7135 tmp4->copyStringInfoFrom(*profile);
7136 idsPerType2.push_back(tmp4);
7137 code[3*i+2]=(int)idsPerType2.size()-1;
7144 std::size_t sz2=idsInPflPerType2.size();
7145 idsInPflPerType.resize(sz2);
7146 for(std::size_t i=0;i<sz2;i++)
7148 DataArrayInt *locDa=idsInPflPerType2[i];
7150 idsInPflPerType[i]=locDa;
7152 std::size_t sz=idsPerType2.size();
7153 idsPerType.resize(sz);
7154 for(std::size_t i=0;i<sz;i++)
7156 DataArrayInt *locDa=idsPerType2[i];
7158 idsPerType[i]=locDa;
7163 * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
7164 * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
7165 * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
7166 * 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.
7168 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *&revDesc, DataArrayInt *&revDescIndx, DataArrayInt *& nM1LevMeshIds, DataArrayInt *&meshnM1Old2New) const
7170 checkFullyDefined();
7171 nM1LevMesh->checkFullyDefined();
7172 if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
7173 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
7174 if(_coords!=nM1LevMesh->getCoords())
7175 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
7176 MCAuto<DataArrayInt> tmp0=DataArrayInt::New();
7177 MCAuto<DataArrayInt> tmp1=DataArrayInt::New();
7178 MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
7179 MCAuto<DataArrayInt> ret0=ret1->sortCellsInMEDFileFrmt();
7180 desc->transformWithIndArr(ret0->getConstPointer(),ret0->getConstPointer()+ret0->getNbOfElems());
7181 MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
7182 tmp->setConnectivity(tmp0,tmp1);
7183 tmp->renumberCells(ret0->getConstPointer(),false);
7184 revDesc=tmp->getNodalConnectivity();
7185 revDescIndx=tmp->getNodalConnectivityIndex();
7186 DataArrayInt *ret=0;
7187 if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
7190 ret->getMaxValue(tmp2);
7192 std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
7193 throw INTERP_KERNEL::Exception(oss.str());
7198 revDescIndx->incrRef();
7201 meshnM1Old2New=ret0;
7206 * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
7207 * necessary for writing the mesh to MED file. Additionally returns a permutation array
7208 * in "Old to New" mode.
7209 * \return DataArrayInt * - a new instance of DataArrayInt. The caller is to delete
7210 * this array using decrRef() as it is no more needed.
7211 * \throw If the nodal connectivity of cells is not defined.
7213 DataArrayInt *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
7215 checkConnectivityFullyDefined();
7216 MCAuto<DataArrayInt> ret=getRenumArrForMEDFileFrmt();
7217 renumberCells(ret->getConstPointer(),false);
7222 * This methods checks that cells are sorted by their types.
7223 * This method makes asumption (no check) that connectivity is correctly set before calling.
7225 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
7227 checkFullyDefined();
7228 const int *conn=_nodal_connec->getConstPointer();
7229 const int *connI=_nodal_connec_index->getConstPointer();
7230 int nbOfCells=getNumberOfCells();
7231 std::set<INTERP_KERNEL::NormalizedCellType> types;
7232 for(const int *i=connI;i!=connI+nbOfCells;)
7234 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7235 if(types.find(curType)!=types.end())
7237 types.insert(curType);
7238 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7244 * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
7245 * The geometric type order is specified by MED file.
7247 * \sa MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
7249 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
7251 return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
7255 * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
7256 * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
7257 * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
7258 * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
7260 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
7262 checkFullyDefined();
7263 const int *conn=_nodal_connec->getConstPointer();
7264 const int *connI=_nodal_connec_index->getConstPointer();
7265 int nbOfCells=getNumberOfCells();
7269 std::set<INTERP_KERNEL::NormalizedCellType> sg;
7270 for(const int *i=connI;i!=connI+nbOfCells;)
7272 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7273 const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
7274 if(isTypeExists!=orderEnd)
7276 int pos=(int)std::distance(orderBg,isTypeExists);
7280 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7284 if(sg.find(curType)==sg.end())
7286 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7297 * This method returns 2 newly allocated DataArrayInt instances. The first is an array of size 'this->getNumberOfCells()' with one component,
7298 * 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
7299 * 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'.
7301 DataArrayInt *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayInt *&nbPerType) const
7303 checkConnectivityFullyDefined();
7304 int nbOfCells=getNumberOfCells();
7305 const int *conn=_nodal_connec->getConstPointer();
7306 const int *connI=_nodal_connec_index->getConstPointer();
7307 MCAuto<DataArrayInt> tmpa=DataArrayInt::New();
7308 MCAuto<DataArrayInt> tmpb=DataArrayInt::New();
7309 tmpa->alloc(nbOfCells,1);
7310 tmpb->alloc((int)std::distance(orderBg,orderEnd),1);
7311 tmpb->fillWithZero();
7312 int *tmp=tmpa->getPointer();
7313 int *tmp2=tmpb->getPointer();
7314 for(const int *i=connI;i!=connI+nbOfCells;i++)
7316 const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
7319 int pos=(int)std::distance(orderBg,where);
7321 tmp[std::distance(connI,i)]=pos;
7325 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
7326 std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
7327 oss << " has a type " << cm.getRepr() << " not in input array of type !";
7328 throw INTERP_KERNEL::Exception(oss.str());
7331 nbPerType=tmpb.retn();
7336 * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
7338 * \return a new object containing the old to new correspondance.
7340 * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
7342 DataArrayInt *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
7344 return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
7348 * 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.
7349 * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
7350 * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
7351 * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
7353 DataArrayInt *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
7355 DataArrayInt *nbPerType=0;
7356 MCAuto<DataArrayInt> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
7357 nbPerType->decrRef();
7358 return tmpa->buildPermArrPerLevel();
7362 * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
7363 * The number of cells remains unchanged after the call of this method.
7364 * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
7365 * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
7367 * \return the array giving the correspondance old to new.
7369 DataArrayInt *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
7371 checkFullyDefined();
7373 const int *conn=_nodal_connec->getConstPointer();
7374 const int *connI=_nodal_connec_index->getConstPointer();
7375 int nbOfCells=getNumberOfCells();
7376 std::vector<INTERP_KERNEL::NormalizedCellType> types;
7377 for(const int *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
7378 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
7380 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7381 types.push_back(curType);
7382 for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
7384 DataArrayInt *ret=DataArrayInt::New();
7385 ret->alloc(nbOfCells,1);
7386 int *retPtr=ret->getPointer();
7387 std::fill(retPtr,retPtr+nbOfCells,-1);
7389 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
7391 for(const int *i=connI;i!=connI+nbOfCells;i++)
7392 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
7393 retPtr[std::distance(connI,i)]=newCellId++;
7395 renumberCells(retPtr,false);
7400 * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
7401 * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
7402 * This method makes asumption that connectivity is correctly set before calling.
7404 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
7406 checkConnectivityFullyDefined();
7407 const int *conn=_nodal_connec->getConstPointer();
7408 const int *connI=_nodal_connec_index->getConstPointer();
7409 int nbOfCells=getNumberOfCells();
7410 std::vector<MEDCouplingUMesh *> ret;
7411 for(const int *i=connI;i!=connI+nbOfCells;)
7413 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7414 int beginCellId=(int)std::distance(connI,i);
7415 i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7416 int endCellId=(int)std::distance(connI,i);
7417 int sz=endCellId-beginCellId;
7418 int *cells=new int[sz];
7419 for(int j=0;j<sz;j++)
7420 cells[j]=beginCellId+j;
7421 MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
7429 * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
7430 * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
7431 * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
7433 * \return a newly allocated instance, that the caller must manage.
7434 * \throw If \a this contains more than one geometric type.
7435 * \throw If the nodal connectivity of \a this is not fully defined.
7436 * \throw If the internal data is not coherent.
7438 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
7440 checkConnectivityFullyDefined();
7441 if(_types.size()!=1)
7442 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7443 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
7444 MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
7445 ret->setCoords(getCoords());
7446 MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
7449 MCAuto<DataArrayInt> c=convertNodalConnectivityToStaticGeoTypeMesh();
7450 retC->setNodalConnectivity(c);
7454 MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
7456 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
7457 DataArrayInt *c=0,*ci=0;
7458 convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
7459 MCAuto<DataArrayInt> cs(c),cis(ci);
7460 retD->setNodalConnectivity(cs,cis);
7465 DataArrayInt *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
7467 checkConnectivityFullyDefined();
7468 if(_types.size()!=1)
7469 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7470 INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
7471 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
7474 std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
7475 oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
7476 throw INTERP_KERNEL::Exception(oss.str());
7478 int nbCells=getNumberOfCells();
7480 int nbNodesPerCell=(int)cm.getNumberOfNodes();
7481 MCAuto<DataArrayInt> connOut=DataArrayInt::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
7482 int *outPtr=connOut->getPointer();
7483 const int *conn=_nodal_connec->begin();
7484 const int *connI=_nodal_connec_index->begin();
7486 for(int i=0;i<nbCells;i++,connI++)
7488 if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
7489 outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
7492 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 << ") !";
7493 throw INTERP_KERNEL::Exception(oss.str());
7496 return connOut.retn();
7500 * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
7501 * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
7505 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayInt *&nodalConn, DataArrayInt *&nodalConnIndex) const
7507 static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
7508 checkConnectivityFullyDefined();
7509 if(_types.size()!=1)
7510 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7511 int nbCells=getNumberOfCells(),lgth=_nodal_connec->getNumberOfTuples();
7513 throw INTERP_KERNEL::Exception(msg0);
7514 MCAuto<DataArrayInt> c(DataArrayInt::New()),ci(DataArrayInt::New());
7515 c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
7516 int *cp(c->getPointer()),*cip(ci->getPointer());
7517 const int *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
7519 for(int i=0;i<nbCells;i++,cip++,incip++)
7521 int strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
7522 int delta(stop-strt);
7525 if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
7526 cp=std::copy(incp+strt,incp+stop,cp);
7528 throw INTERP_KERNEL::Exception(msg0);
7531 throw INTERP_KERNEL::Exception(msg0);
7532 cip[1]=cip[0]+delta;
7534 nodalConn=c.retn(); nodalConnIndex=ci.retn();
7538 * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
7539 * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
7540 * This method is particulary useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
7541 * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
7542 * are not used here to avoid the build of big permutation array.
7544 * \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
7545 * those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
7546 * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayInt instance whose number of tuples is equal to the number of chunks of same geotype
7547 * in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
7548 * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayInt instance having the same size than \b szOfCellGrpOfSameType. This
7549 * output array gives for each chunck of same type the corresponding mesh id in \b ms.
7550 * \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
7551 * is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
7553 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
7554 DataArrayInt *&szOfCellGrpOfSameType,
7555 DataArrayInt *&idInMsOfCellGrpOfSameType)
7557 std::vector<const MEDCouplingUMesh *> ms2;
7558 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
7561 (*it)->checkConnectivityFullyDefined();
7565 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
7566 const DataArrayDouble *refCoo=ms2[0]->getCoords();
7567 int meshDim=ms2[0]->getMeshDimension();
7568 std::vector<const MEDCouplingUMesh *> m1ssm;
7569 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
7571 std::vector<const MEDCouplingUMesh *> m1ssmSingle;
7572 std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
7574 MCAuto<DataArrayInt> ret1(DataArrayInt::New()),ret2(DataArrayInt::New());
7575 ret1->alloc(0,1); ret2->alloc(0,1);
7576 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
7578 if(meshDim!=(*it)->getMeshDimension())
7579 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
7580 if(refCoo!=(*it)->getCoords())
7581 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
7582 std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
7583 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
7584 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
7585 for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
7587 MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
7588 m1ssmSingleAuto.push_back(singleCell);
7589 m1ssmSingle.push_back(singleCell);
7590 ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
7593 MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
7594 MCAuto<DataArrayInt> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
7595 std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
7596 for(std::size_t i=0;i<m1ssm.size();i++)
7597 m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
7598 MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
7599 szOfCellGrpOfSameType=ret1->renumber(renum->getConstPointer());
7600 idInMsOfCellGrpOfSameType=ret2->renumber(renum->getConstPointer());
7605 * This method returns a newly created DataArrayInt instance.
7606 * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
7608 DataArrayInt *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const int *begin, const int *end) const
7610 checkFullyDefined();
7611 const int *conn=_nodal_connec->getConstPointer();
7612 const int *connIndex=_nodal_connec_index->getConstPointer();
7613 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
7614 for(const int *w=begin;w!=end;w++)
7615 if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
7616 ret->pushBackSilent(*w);
7621 * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
7622 * are in [0:getNumberOfCells())
7624 DataArrayInt *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayInt *da) const
7626 checkFullyDefined();
7627 const int *conn=_nodal_connec->getConstPointer();
7628 const int *connI=_nodal_connec_index->getConstPointer();
7629 int nbOfCells=getNumberOfCells();
7630 std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
7631 int *tmp=new int[nbOfCells];
7632 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
7635 for(const int *i=connI;i!=connI+nbOfCells;i++)
7636 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
7637 tmp[std::distance(connI,i)]=j++;
7639 DataArrayInt *ret=DataArrayInt::New();
7640 ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
7641 ret->copyStringInfoFrom(*da);
7642 int *retPtr=ret->getPointer();
7643 const int *daPtr=da->getConstPointer();
7644 int nbOfElems=da->getNbOfElems();
7645 for(int k=0;k<nbOfElems;k++)
7646 retPtr[k]=tmp[daPtr[k]];
7652 * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
7653 * This method \b works \b for mesh sorted by type.
7654 * cells whose ids is in 'idsPerGeoType' array.
7655 * This method conserves coords and name of mesh.
7657 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const int *idsPerGeoTypeBg, const int *idsPerGeoTypeEnd) const
7659 std::vector<int> code=getDistributionOfTypes();
7660 std::size_t nOfTypesInThis=code.size()/3;
7661 int sz=0,szOfType=0;
7662 for(std::size_t i=0;i<nOfTypesInThis;i++)
7667 szOfType=code[3*i+1];
7669 for(const int *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
7670 if(*work<0 || *work>=szOfType)
7672 std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
7673 oss << ". It should be in [0," << szOfType << ") !";
7674 throw INTERP_KERNEL::Exception(oss.str());
7676 MCAuto<DataArrayInt> idsTokeep=DataArrayInt::New(); idsTokeep->alloc(sz+(int)std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
7677 int *idsPtr=idsTokeep->getPointer();
7679 for(std::size_t i=0;i<nOfTypesInThis;i++)
7682 for(int j=0;j<code[3*i+1];j++)
7685 idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind2nd(std::plus<int>(),offset));
7686 offset+=code[3*i+1];
7688 MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
7689 ret->copyTinyInfoFrom(this);
7694 * This method returns a vector of size 'this->getNumberOfCells()'.
7695 * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
7697 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
7699 int ncell=getNumberOfCells();
7700 std::vector<bool> ret(ncell);
7701 const int *cI=getNodalConnectivityIndex()->getConstPointer();
7702 const int *c=getNodalConnectivity()->getConstPointer();
7703 for(int i=0;i<ncell;i++)
7705 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
7706 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
7707 ret[i]=cm.isQuadratic();
7713 * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
7715 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
7717 if(other->getType()!=UNSTRUCTURED)
7718 throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
7719 const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
7720 return MergeUMeshes(this,otherC);
7724 * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
7725 * computed by averaging coordinates of cell nodes, so this method is not a right
7726 * choice for degnerated meshes (not well oriented, cells with measure close to zero).
7727 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
7728 * this->getNumberOfCells() tuples per \a this->getSpaceDimension()
7729 * components. The caller is to delete this array using decrRef() as it is
7731 * \throw If the coordinates array is not set.
7732 * \throw If the nodal connectivity of cells is not defined.
7733 * \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
7735 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
7737 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
7738 int spaceDim=getSpaceDimension();
7739 int nbOfCells=getNumberOfCells();
7740 ret->alloc(nbOfCells,spaceDim);
7741 ret->copyStringInfoFrom(*getCoords());
7742 double *ptToFill=ret->getPointer();
7743 const int *nodal=_nodal_connec->getConstPointer();
7744 const int *nodalI=_nodal_connec_index->getConstPointer();
7745 const double *coor=_coords->getConstPointer();
7746 for(int i=0;i<nbOfCells;i++)
7748 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
7749 INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
7756 * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
7757 * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
7759 * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
7760 * DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
7762 * \sa MEDCouplingUMesh::computeCellCenterOfMass
7763 * \throw If \a this is not fully defined (coordinates and connectivity)
7764 * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
7766 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
7768 checkFullyDefined();
7769 MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
7770 int spaceDim=getSpaceDimension();
7771 int nbOfCells=getNumberOfCells();
7772 int nbOfNodes=getNumberOfNodes();
7773 ret->alloc(nbOfCells,spaceDim);
7774 double *ptToFill=ret->getPointer();
7775 const int *nodal=_nodal_connec->getConstPointer();
7776 const int *nodalI=_nodal_connec_index->getConstPointer();
7777 const double *coor=_coords->getConstPointer();
7778 for(int i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
7780 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
7781 std::fill(ptToFill,ptToFill+spaceDim,0.);
7782 if(type!=INTERP_KERNEL::NORM_POLYHED)
7784 for(const int *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
7786 if(*conn>=0 && *conn<nbOfNodes)
7787 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
7790 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," << nbOfNodes << ") !";
7791 throw INTERP_KERNEL::Exception(oss.str());
7794 int nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
7795 if(nbOfNodesInCell>0)
7796 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
7799 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
7800 throw INTERP_KERNEL::Exception(oss.str());
7805 std::set<int> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
7807 for(std::set<int>::const_iterator it=s.begin();it!=s.end();it++)
7809 if(*it>=0 && *it<nbOfNodes)
7810 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
7813 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," << nbOfNodes << ") !";
7814 throw INTERP_KERNEL::Exception(oss.str());
7818 std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)s.size()));
7821 std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
7822 throw INTERP_KERNEL::Exception(oss.str());
7830 * Returns a new DataArrayDouble holding barycenters of specified cells. The
7831 * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
7832 * are specified via an array of cell ids.
7833 * \warning Validity of the specified cell ids is not checked!
7834 * Valid range is [ 0, \a this->getNumberOfCells() ).
7835 * \param [in] begin - an array of cell ids of interest.
7836 * \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
7837 * \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
7838 * end - \a begin ) tuples per \a this->getSpaceDimension() components. The
7839 * caller is to delete this array using decrRef() as it is no more needed.
7840 * \throw If the coordinates array is not set.
7841 * \throw If the nodal connectivity of cells is not defined.
7843 * \if ENABLE_EXAMPLES
7844 * \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
7845 * \ref py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
7848 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const int *begin, const int *end) const
7850 DataArrayDouble *ret=DataArrayDouble::New();
7851 int spaceDim=getSpaceDimension();
7852 int nbOfTuple=(int)std::distance(begin,end);
7853 ret->alloc(nbOfTuple,spaceDim);
7854 double *ptToFill=ret->getPointer();
7855 double *tmp=new double[spaceDim];
7856 const int *nodal=_nodal_connec->getConstPointer();
7857 const int *nodalI=_nodal_connec_index->getConstPointer();
7858 const double *coor=_coords->getConstPointer();
7859 for(const int *w=begin;w!=end;w++)
7861 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
7862 INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
7870 * 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".
7871 * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
7872 * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
7873 * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
7874 * This method is useful to detect 2D cells in 3D space that are not coplanar.
7876 * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
7877 * \throw If spaceDim!=3 or meshDim!=2.
7878 * \throw If connectivity of \a this is invalid.
7879 * \throw If connectivity of a cell in \a this points to an invalid node.
7881 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
7883 MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
7884 int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
7885 if(getSpaceDimension()!=3 || getMeshDimension()!=2)
7886 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
7887 ret->alloc(nbOfCells,4);
7888 double *retPtr(ret->getPointer());
7889 const int *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
7890 const double *coor(_coords->begin());
7891 for(int i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
7893 double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
7894 if(nodalI[1]-nodalI[0]>=3)
7896 for(int j=0;j<3;j++)
7898 int nodeId(nodal[nodalI[0]+1+j]);
7899 if(nodeId>=0 && nodeId<nbOfNodes)
7900 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
7903 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
7904 throw INTERP_KERNEL::Exception(oss.str());
7910 std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
7911 throw INTERP_KERNEL::Exception(oss.str());
7913 INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
7914 retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
7920 * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
7923 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
7926 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
7927 da->checkAllocated();
7928 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(da->getName(),0);
7930 int nbOfTuples=da->getNumberOfTuples();
7931 MCAuto<DataArrayInt> c=DataArrayInt::New();
7932 MCAuto<DataArrayInt> cI=DataArrayInt::New();
7933 c->alloc(2*nbOfTuples,1);
7934 cI->alloc(nbOfTuples+1,1);
7935 int *cp=c->getPointer();
7936 int *cip=cI->getPointer();
7938 for(int i=0;i<nbOfTuples;i++)
7940 *cp++=INTERP_KERNEL::NORM_POINT1;
7944 ret->setConnectivity(c,cI,true);
7948 * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
7949 * Cells and nodes of
7950 * the first mesh precede cells and nodes of the second mesh within the result mesh.
7951 * \param [in] mesh1 - the first mesh.
7952 * \param [in] mesh2 - the second mesh.
7953 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7954 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7955 * is no more needed.
7956 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
7957 * \throw If the coordinates array is not set in none of the meshes.
7958 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
7959 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
7961 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
7963 std::vector<const MEDCouplingUMesh *> tmp(2);
7964 tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
7965 return MergeUMeshes(tmp);
7969 * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
7970 * Cells and nodes of
7971 * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
7972 * \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
7973 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7974 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7975 * is no more needed.
7976 * \throw If \a a.size() == 0.
7977 * \throw If \a a[ *i* ] == NULL.
7978 * \throw If the coordinates array is not set in none of the meshes.
7979 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
7980 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
7982 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(std::vector<const MEDCouplingUMesh *>& a)
7984 std::size_t sz=a.size();
7986 return MergeUMeshesLL(a);
7987 for(std::size_t ii=0;ii<sz;ii++)
7990 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
7991 throw INTERP_KERNEL::Exception(oss.str());
7993 std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
7994 std::vector< const MEDCouplingUMesh * > aa(sz);
7996 for(std::size_t i=0;i<sz && spaceDim==-3;i++)
7998 const MEDCouplingUMesh *cur=a[i];
7999 const DataArrayDouble *coo=cur->getCoords();
8001 spaceDim=coo->getNumberOfComponents();
8004 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
8005 for(std::size_t i=0;i<sz;i++)
8007 bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
8010 return MergeUMeshesLL(aa);
8015 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesLL(std::vector<const MEDCouplingUMesh *>& a)
8018 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : input array must be NON EMPTY !");
8019 std::vector<const MEDCouplingUMesh *>::const_iterator it=a.begin();
8020 int meshDim=(*it)->getMeshDimension();
8021 int nbOfCells=(*it)->getNumberOfCells();
8022 int meshLgth=(*it++)->getNodalConnectivityArrayLen();
8023 for(;it!=a.end();it++)
8025 if(meshDim!=(*it)->getMeshDimension())
8026 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, MergeUMeshes impossible !");
8027 nbOfCells+=(*it)->getNumberOfCells();
8028 meshLgth+=(*it)->getNodalConnectivityArrayLen();
8030 std::vector<const MEDCouplingPointSet *> aps(a.size());
8031 std::copy(a.begin(),a.end(),aps.begin());
8032 MCAuto<DataArrayDouble> pts=MergeNodesArray(aps);
8033 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("merge",meshDim);
8034 ret->setCoords(pts);
8035 MCAuto<DataArrayInt> c=DataArrayInt::New();
8036 c->alloc(meshLgth,1);
8037 int *cPtr=c->getPointer();
8038 MCAuto<DataArrayInt> cI=DataArrayInt::New();
8039 cI->alloc(nbOfCells+1,1);
8040 int *cIPtr=cI->getPointer();
8044 for(it=a.begin();it!=a.end();it++)
8046 int curNbOfCell=(*it)->getNumberOfCells();
8047 const int *curCI=(*it)->_nodal_connec_index->getConstPointer();
8048 const int *curC=(*it)->_nodal_connec->getConstPointer();
8049 cIPtr=std::transform(curCI+1,curCI+curNbOfCell+1,cIPtr,std::bind2nd(std::plus<int>(),offset));
8050 for(int j=0;j<curNbOfCell;j++)
8052 const int *src=curC+curCI[j];
8054 for(;src!=curC+curCI[j+1];src++,cPtr++)
8062 offset+=curCI[curNbOfCell];
8063 offset2+=(*it)->getNumberOfNodes();
8066 ret->setConnectivity(c,cI,true);
8073 * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
8074 * dimension and sharing the node coordinates array.
8075 * All cells of the first mesh precede all cells of the second mesh
8076 * within the result mesh.
8077 * \param [in] mesh1 - the first mesh.
8078 * \param [in] mesh2 - the second mesh.
8079 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8080 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8081 * is no more needed.
8082 * \throw If \a mesh1 == NULL or \a mesh2 == NULL.
8083 * \throw If the meshes do not share the node coordinates array.
8084 * \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
8085 * \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
8087 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
8089 std::vector<const MEDCouplingUMesh *> tmp(2);
8090 tmp[0]=mesh1; tmp[1]=mesh2;
8091 return MergeUMeshesOnSameCoords(tmp);
8095 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
8096 * dimension and sharing the node coordinates array.
8097 * All cells of the *i*-th mesh precede all cells of the
8098 * (*i*+1)-th mesh within the result mesh.
8099 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
8100 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8101 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8102 * is no more needed.
8103 * \throw If \a a.size() == 0.
8104 * \throw If \a a[ *i* ] == NULL.
8105 * \throw If the meshes do not share the node coordinates array.
8106 * \throw If \a a[ *i* ]->getMeshDimension() < 0.
8107 * \throw If the meshes in \a a are of different dimension (getMeshDimension()).
8109 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
8112 throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
8113 for(std::size_t ii=0;ii<meshes.size();ii++)
8116 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
8117 throw INTERP_KERNEL::Exception(oss.str());
8119 const DataArrayDouble *coords=meshes.front()->getCoords();
8120 int meshDim=meshes.front()->getMeshDimension();
8121 std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
8123 int meshIndexLgth=0;
8124 for(;iter!=meshes.end();iter++)
8126 if(coords!=(*iter)->getCoords())
8127 throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
8128 if(meshDim!=(*iter)->getMeshDimension())
8129 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
8130 meshLgth+=(*iter)->getNodalConnectivityArrayLen();
8131 meshIndexLgth+=(*iter)->getNumberOfCells();
8133 MCAuto<DataArrayInt> nodal=DataArrayInt::New();
8134 nodal->alloc(meshLgth,1);
8135 int *nodalPtr=nodal->getPointer();
8136 MCAuto<DataArrayInt> nodalIndex=DataArrayInt::New();
8137 nodalIndex->alloc(meshIndexLgth+1,1);
8138 int *nodalIndexPtr=nodalIndex->getPointer();
8140 for(iter=meshes.begin();iter!=meshes.end();iter++)
8142 const int *nod=(*iter)->getNodalConnectivity()->getConstPointer();
8143 const int *index=(*iter)->getNodalConnectivityIndex()->getConstPointer();
8144 int nbOfCells=(*iter)->getNumberOfCells();
8145 int meshLgth2=(*iter)->getNodalConnectivityArrayLen();
8146 nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
8147 if(iter!=meshes.begin())
8148 nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind2nd(std::plus<int>(),offset));
8150 nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
8153 MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
8154 ret->setName("merge");
8155 ret->setMeshDimension(meshDim);
8156 ret->setConnectivity(nodal,nodalIndex,true);
8157 ret->setCoords(coords);
8162 * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
8163 * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
8164 * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
8165 * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
8166 * New" mode are returned for each input mesh.
8167 * \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
8168 * \param [in] compType - specifies a cell comparison technique. For meaning of its
8169 * valid values [0,1,2], see zipConnectivityTraducer().
8170 * \param [in,out] corr - an array of DataArrayInt, of the same size as \a
8171 * meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
8172 * mesh. The caller is to delete each of the arrays using decrRef() as it is
8174 * \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8175 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8176 * is no more needed.
8177 * \throw If \a meshes.size() == 0.
8178 * \throw If \a meshes[ *i* ] == NULL.
8179 * \throw If the meshes do not share the node coordinates array.
8180 * \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
8181 * \throw If the \a meshes are of different dimension (getMeshDimension()).
8182 * \throw If the nodal connectivity of cells of any of \a meshes is not defined.
8183 * \throw If the nodal connectivity any of \a meshes includes an invalid id.
8185 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayInt *>& corr)
8187 //All checks are delegated to MergeUMeshesOnSameCoords
8188 MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
8189 MCAuto<DataArrayInt> o2n=ret->zipConnectivityTraducer(compType);
8190 corr.resize(meshes.size());
8191 std::size_t nbOfMeshes=meshes.size();
8193 const int *o2nPtr=o2n->getConstPointer();
8194 for(std::size_t i=0;i<nbOfMeshes;i++)
8196 DataArrayInt *tmp=DataArrayInt::New();
8197 int curNbOfCells=meshes[i]->getNumberOfCells();
8198 tmp->alloc(curNbOfCells,1);
8199 std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
8200 offset+=curNbOfCells;
8201 tmp->setName(meshes[i]->getName());
8208 * Makes all given meshes share the nodal connectivity array. The common connectivity
8209 * array is created by concatenating the connectivity arrays of all given meshes. All
8210 * the given meshes must be of the same space dimension but dimension of cells **can
8211 * differ**. This method is particulary useful in MEDLoader context to build a \ref
8212 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
8213 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
8214 * \param [in,out] meshes - a vector of meshes to update.
8215 * \throw If any of \a meshes is NULL.
8216 * \throw If the coordinates array is not set in any of \a meshes.
8217 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
8218 * \throw If \a meshes are of different space dimension.
8220 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
8222 std::size_t sz=meshes.size();
8225 std::vector< const DataArrayDouble * > coords(meshes.size());
8226 std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
8227 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
8231 (*it)->checkConnectivityFullyDefined();
8232 const DataArrayDouble *coo=(*it)->getCoords();
8237 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
8238 oss << " has no coordinate array defined !";
8239 throw INTERP_KERNEL::Exception(oss.str());
8244 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
8245 oss << " is null !";
8246 throw INTERP_KERNEL::Exception(oss.str());
8249 MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
8250 std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
8251 int offset=(*it)->getNumberOfNodes();
8252 (*it++)->setCoords(res);
8253 for(;it!=meshes.end();it++)
8255 int oldNumberOfNodes=(*it)->getNumberOfNodes();
8256 (*it)->setCoords(res);
8257 (*it)->shiftNodeNumbersInConn(offset);
8258 offset+=oldNumberOfNodes;
8263 * Merges nodes coincident with a given precision within all given meshes that share
8264 * the nodal connectivity array. The given meshes **can be of different** mesh
8265 * dimension. This method is particulary useful in MEDLoader context to build a \ref
8266 * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
8267 * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
8268 * \param [in,out] meshes - a vector of meshes to update.
8269 * \param [in] eps - the precision used to detect coincident nodes (infinite norm).
8270 * \throw If any of \a meshes is NULL.
8271 * \throw If the \a meshes do not share the same node coordinates array.
8272 * \throw If the nodal connectivity of cells is not defined in any of \a meshes.
8274 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
8278 std::set<const DataArrayDouble *> s;
8279 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
8282 s.insert((*it)->getCoords());
8285 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 !";
8286 throw INTERP_KERNEL::Exception(oss.str());
8291 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 !";
8292 throw INTERP_KERNEL::Exception(oss.str());
8294 const DataArrayDouble *coo=*(s.begin());
8298 DataArrayInt *comm,*commI;
8299 coo->findCommonTuples(eps,-1,comm,commI);
8300 MCAuto<DataArrayInt> tmp1(comm),tmp2(commI);
8301 int oldNbOfNodes=coo->getNumberOfTuples();
8303 MCAuto<DataArrayInt> o2n=DataArrayInt::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
8304 if(oldNbOfNodes==newNbOfNodes)
8306 MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->getConstPointer(),newNbOfNodes);
8307 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
8309 (*it)->renumberNodesInConn(o2n->getConstPointer());
8310 (*it)->setCoords(newCoords);
8315 * 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.
8316 * \param nbOfNodesPerLev in parameter that specifies the number of nodes of one slice of global dataset
8317 * \param isQuad specifies the policy of connectivity.
8318 * @ret in/out parameter in which the result will be append
8320 void MEDCouplingUMesh::AppendExtrudedCell(const int *connBg, const int *connEnd, int nbOfNodesPerLev, bool isQuad, std::vector<int>& ret)
8322 INTERP_KERNEL::NormalizedCellType flatType=(INTERP_KERNEL::NormalizedCellType)connBg[0];
8323 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(flatType);
8324 ret.push_back(cm.getExtrudedType());
8325 int deltaz=isQuad?2*nbOfNodesPerLev:nbOfNodesPerLev;
8328 case INTERP_KERNEL::NORM_POINT1:
8330 ret.push_back(connBg[1]);
8331 ret.push_back(connBg[1]+nbOfNodesPerLev);
8334 case INTERP_KERNEL::NORM_SEG2:
8336 int conn[4]={connBg[1],connBg[2],connBg[2]+deltaz,connBg[1]+deltaz};
8337 ret.insert(ret.end(),conn,conn+4);
8340 case INTERP_KERNEL::NORM_SEG3:
8342 int conn[8]={connBg[1],connBg[3],connBg[3]+deltaz,connBg[1]+deltaz,connBg[2],connBg[3]+nbOfNodesPerLev,connBg[2]+deltaz,connBg[1]+nbOfNodesPerLev};
8343 ret.insert(ret.end(),conn,conn+8);
8346 case INTERP_KERNEL::NORM_QUAD4:
8348 int conn[8]={connBg[1],connBg[2],connBg[3],connBg[4],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4]+deltaz};
8349 ret.insert(ret.end(),conn,conn+8);
8352 case INTERP_KERNEL::NORM_TRI3:
8354 int conn[6]={connBg[1],connBg[2],connBg[3],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz};
8355 ret.insert(ret.end(),conn,conn+6);
8358 case INTERP_KERNEL::NORM_TRI6:
8360 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,
8361 connBg[1]+nbOfNodesPerLev,connBg[2]+nbOfNodesPerLev,connBg[3]+nbOfNodesPerLev};
8362 ret.insert(ret.end(),conn,conn+15);
8365 case INTERP_KERNEL::NORM_QUAD8:
8368 connBg[1],connBg[2],connBg[3],connBg[4],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4]+deltaz,
8369 connBg[5],connBg[6],connBg[7],connBg[8],connBg[5]+deltaz,connBg[6]+deltaz,connBg[7]+deltaz,connBg[8]+deltaz,
8370 connBg[1]+nbOfNodesPerLev,connBg[2]+nbOfNodesPerLev,connBg[3]+nbOfNodesPerLev,connBg[4]+nbOfNodesPerLev
8372 ret.insert(ret.end(),conn,conn+20);
8375 case INTERP_KERNEL::NORM_POLYGON:
8377 std::back_insert_iterator< std::vector<int> > ii(ret);
8378 std::copy(connBg+1,connEnd,ii);
8380 std::reverse_iterator<const int *> rConnBg(connEnd);
8381 std::reverse_iterator<const int *> rConnEnd(connBg+1);
8382 std::transform(rConnBg,rConnEnd,ii,std::bind2nd(std::plus<int>(),deltaz));
8383 std::size_t nbOfRadFaces=std::distance(connBg+1,connEnd);
8384 for(std::size_t i=0;i<nbOfRadFaces;i++)
8387 int conn[4]={connBg[(i+1)%nbOfRadFaces+1],connBg[i+1],connBg[i+1]+deltaz,connBg[(i+1)%nbOfRadFaces+1]+deltaz};
8388 std::copy(conn,conn+4,ii);
8393 throw INTERP_KERNEL::Exception("A flat type has been detected that has not its extruded representation !");
8398 * This static operates only for coords in 3D. The polygon is specfied by its connectivity nodes in [ \a begin , \a end ).
8400 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const int *begin, const int *end, const double *coords)
8403 double v[3]={0.,0.,0.};
8404 std::size_t sz=std::distance(begin,end);
8409 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];
8410 v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
8411 v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
8413 double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
8415 // Try using quadratic points if standard points are degenerated (for example a QPOLYG with two
8416 // SEG3 forming a circle):
8417 if (fabs(ret) < INTERP_KERNEL::DEFAULT_ABS_TOL && isQuadratic)
8419 v[0] = 0.0; v[1] = 0.0; v[2] = 0.0;
8420 for(std::size_t j=0;j<sz;j++)
8422 if (j%2) // current point i is quadratic, next point i+1 is standard
8425 ip1 = (j+1)%sz; // ip1 = "i+1"
8427 else // current point i is standard, next point i+1 is quadratic
8432 v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
8433 v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
8434 v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
8436 ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
8442 * The polyhedron is specfied by its connectivity nodes in [ \a begin , \a end ).
8444 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const int *begin, const int *end, const double *coords)
8446 std::vector<std::pair<int,int> > edges;
8447 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
8448 const int *bgFace=begin;
8449 for(std::size_t i=0;i<nbOfFaces;i++)
8451 const int *endFace=std::find(bgFace+1,end,-1);
8452 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
8453 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8455 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8456 if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
8458 edges.push_back(p1);
8462 return INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)>-EPS_FOR_POLYH_ORIENTATION;
8466 * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
8468 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const int *begin, const int *end, const double *coords)
8470 double vec0[3],vec1[3];
8471 std::size_t sz=std::distance(begin,end);
8473 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
8474 int nbOfNodes=(int)sz/2;
8475 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
8476 const double *pt0=coords+3*begin[0];
8477 const double *pt1=coords+3*begin[nbOfNodes];
8478 vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
8479 return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
8482 void MEDCouplingUMesh::CorrectExtrudedStaticCell(int *begin, int *end)
8484 std::size_t sz=std::distance(begin,end);
8485 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
8486 std::size_t nbOfNodes(sz/2);
8487 std::copy(begin,end,(int *)tmp);
8488 for(std::size_t j=1;j<nbOfNodes;j++)
8490 begin[j]=tmp[nbOfNodes-j];
8491 begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
8495 bool MEDCouplingUMesh::IsTetra4WellOriented(const int *begin, const int *end, const double *coords)
8497 std::size_t sz=std::distance(begin,end);
8499 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
8500 double vec0[3],vec1[3];
8501 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
8502 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];
8503 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;
8506 bool MEDCouplingUMesh::IsPyra5WellOriented(const int *begin, const int *end, const double *coords)
8508 std::size_t sz=std::distance(begin,end);
8510 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
8512 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
8513 const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
8514 return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
8518 * 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 )
8519 * 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
8522 * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
8523 * \param [in] coords the coordinates with nb of components exactly equal to 3
8524 * \param [in] begin begin of the nodal connectivity (geometric type included) of a single polyhedron cell
8525 * \param [in] end end of nodal connectivity of a single polyhedron cell (excluded)
8526 * \param [out] res the result is put at the end of the vector without any alteration of the data.
8528 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, const int *begin, const int *end, DataArrayInt *res)
8530 int nbFaces=std::count(begin+1,end,-1)+1;
8531 MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
8532 double *vPtr=v->getPointer();
8533 MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,1);
8534 double *pPtr=p->getPointer();
8535 const int *stFaceConn=begin+1;
8536 for(int i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
8538 const int *endFaceConn=std::find(stFaceConn,end,-1);
8539 ComputeVecAndPtOfFace(eps,coords->getConstPointer(),stFaceConn,endFaceConn,vPtr,pPtr);
8540 stFaceConn=endFaceConn+1;
8542 pPtr=p->getPointer(); vPtr=v->getPointer();
8543 DataArrayInt *comm1=0,*commI1=0;
8544 v->findCommonTuples(eps,-1,comm1,commI1);
8545 MCAuto<DataArrayInt> comm1Auto(comm1),commI1Auto(commI1);
8546 const int *comm1Ptr=comm1->getConstPointer();
8547 const int *commI1Ptr=commI1->getConstPointer();
8548 int nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
8549 res->pushBackSilent((int)INTERP_KERNEL::NORM_POLYHED);
8551 MCAuto<MEDCouplingUMesh> mm=MEDCouplingUMesh::New("",3);
8552 mm->setCoords(const_cast<DataArrayDouble *>(coords)); mm->allocateCells(1); mm->insertNextCell(INTERP_KERNEL::NORM_POLYHED,(int)std::distance(begin+1,end),begin+1);
8553 mm->finishInsertingCells();
8555 for(int i=0;i<nbOfGrps1;i++)
8557 int vecId=comm1Ptr[commI1Ptr[i]];
8558 MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
8559 DataArrayInt *comm2=0,*commI2=0;
8560 tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
8561 MCAuto<DataArrayInt> comm2Auto(comm2),commI2Auto(commI2);
8562 const int *comm2Ptr=comm2->getConstPointer();
8563 const int *commI2Ptr=commI2->getConstPointer();
8564 int nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
8565 for(int j=0;j<nbOfGrps2;j++)
8567 if(commI2Ptr[j+1]-commI2Ptr[j]<=1)
8569 res->insertAtTheEnd(begin,end);
8570 res->pushBackSilent(-1);
8574 int pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
8575 MCAuto<DataArrayInt> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
8576 ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
8577 DataArrayInt *tmp0=DataArrayInt::New(),*tmp1=DataArrayInt::New(),*tmp2=DataArrayInt::New(),*tmp3=DataArrayInt::New();
8578 MCAuto<MEDCouplingUMesh> mm2=mm->buildDescendingConnectivity(tmp0,tmp1,tmp2,tmp3); tmp0->decrRef(); tmp1->decrRef(); tmp2->decrRef(); tmp3->decrRef();
8579 MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(mm2->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
8580 MCAuto<DataArrayInt> idsNodeTmp=mm3->zipCoordsTraducer();
8581 MCAuto<DataArrayInt> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
8582 const int *idsNodePtr=idsNode->getConstPointer();
8583 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];
8584 double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
8585 double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
8586 if(std::abs(norm)>eps)
8588 double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
8589 mm3->rotate(center,vec,angle);
8591 mm3->changeSpaceDimension(2);
8592 MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
8593 const int *conn4=mm4->getNodalConnectivity()->getConstPointer();
8594 const int *connI4=mm4->getNodalConnectivityIndex()->getConstPointer();
8595 int nbOfCells=mm4->getNumberOfCells();
8596 for(int k=0;k<nbOfCells;k++)
8599 for(const int *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
8600 res->pushBackSilent(idsNodePtr[*work]);
8601 res->pushBackSilent(-1);
8606 res->popBackSilent();
8610 * 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
8611 * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
8613 * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
8614 * \param [in] coords coordinates expected to have 3 components.
8615 * \param [in] begin start of the nodal connectivity of the face.
8616 * \param [in] end end of the nodal connectivity (excluded) of the face.
8617 * \param [out] v the normalized vector of size 3
8618 * \param [out] p the pos of plane
8620 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const int *begin, const int *end, double *v, double *p)
8622 std::size_t nbPoints=std::distance(begin,end);
8624 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
8625 double vec[3]={0.,0.,0.};
8627 bool refFound=false;
8628 for(;j<nbPoints-1 && !refFound;j++)
8630 vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
8631 vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
8632 vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
8633 double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
8637 vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
8640 for(std::size_t i=j;i<nbPoints-1;i++)
8643 curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
8644 curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
8645 curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
8646 double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
8649 curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
8650 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];
8651 norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
8654 v[0]/=norm; v[1]/=norm; v[2]/=norm;
8655 *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
8659 throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
8663 * This method tries to obtain a well oriented polyhedron.
8664 * If the algorithm fails, an exception will be thrown.
8666 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(int *begin, int *end, const double *coords)
8668 std::list< std::pair<int,int> > edgesOK,edgesFinished;
8669 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
8670 std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
8672 int *bgFace=begin,*endFace=std::find(begin+1,end,-1);
8673 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
8674 for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<int,int> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
8676 while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
8679 std::size_t smthChanged=0;
8680 for(std::size_t i=0;i<nbOfFaces;i++)
8682 endFace=std::find(bgFace+1,end,-1);
8683 nbOfEdgesInFace=std::distance(bgFace,endFace);
8687 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8689 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8690 std::pair<int,int> p2(p1.second,p1.first);
8691 bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
8692 bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
8693 if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
8698 std::reverse(bgFace+1,endFace);
8699 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8701 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8702 std::pair<int,int> p2(p1.second,p1.first);
8703 if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
8704 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
8705 if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
8706 { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
8707 std::list< std::pair<int,int> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
8708 if(it!=edgesOK.end())
8711 edgesFinished.push_back(p1);
8714 edgesOK.push_back(p1);
8721 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
8723 if(!edgesOK.empty())
8724 { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
8725 if(INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)<-EPS_FOR_POLYH_ORIENTATION)
8726 {//not lucky ! The first face was not correctly oriented : reorient all faces...
8728 for(std::size_t i=0;i<nbOfFaces;i++)
8730 endFace=std::find(bgFace+1,end,-1);
8731 std::reverse(bgFace+1,endFace);
8737 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMeshLinear(const MEDCouplingUMesh *skin, const DataArrayInt *n2o) const
8739 int nbOfNodesExpected(skin->getNumberOfNodes());
8740 const int *n2oPtr(n2o->getConstPointer());
8741 MCAuto<DataArrayInt> revNodal(DataArrayInt::New()),revNodalI(DataArrayInt::New());
8742 skin->getReverseNodalConnectivity(revNodal,revNodalI);
8743 const int *revNodalPtr(revNodal->getConstPointer()),*revNodalIPtr(revNodalI->getConstPointer());
8744 const int *nodalPtr(skin->getNodalConnectivity()->getConstPointer());
8745 const int *nodalIPtr(skin->getNodalConnectivityIndex()->getConstPointer());
8746 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfNodesExpected+1,1);
8747 int *work(ret->getPointer()); *work++=INTERP_KERNEL::NORM_POLYGON;
8748 if(nbOfNodesExpected<1)
8750 int prevCell(0),prevNode(nodalPtr[nodalIPtr[0]+1]);
8751 *work++=n2oPtr[prevNode];
8752 for(int i=1;i<nbOfNodesExpected;i++)
8754 if(nodalIPtr[prevCell+1]-nodalIPtr[prevCell]==3)
8756 std::set<int> conn(nodalPtr+nodalIPtr[prevCell]+1,nodalPtr+nodalIPtr[prevCell]+3);
8757 conn.erase(prevNode);
8760 int curNode(*(conn.begin()));
8761 *work++=n2oPtr[curNode];
8762 std::set<int> shar(revNodalPtr+revNodalIPtr[curNode],revNodalPtr+revNodalIPtr[curNode+1]);
8763 shar.erase(prevCell);
8766 prevCell=*(shar.begin());
8770 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected 2 !");
8773 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected 1 !");
8776 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected cell !");
8781 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMeshQuadratic(const MEDCouplingUMesh *skin, const DataArrayInt *n2o) const
8783 int nbOfNodesExpected(skin->getNumberOfNodes());
8784 int nbOfTurn(nbOfNodesExpected/2);
8785 const int *n2oPtr(n2o->getConstPointer());
8786 MCAuto<DataArrayInt> revNodal(DataArrayInt::New()),revNodalI(DataArrayInt::New());
8787 skin->getReverseNodalConnectivity(revNodal,revNodalI);
8788 const int *revNodalPtr(revNodal->getConstPointer()),*revNodalIPtr(revNodalI->getConstPointer());
8789 const int *nodalPtr(skin->getNodalConnectivity()->getConstPointer());
8790 const int *nodalIPtr(skin->getNodalConnectivityIndex()->getConstPointer());
8791 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfNodesExpected+1,1);
8792 int *work(ret->getPointer()); *work++=INTERP_KERNEL::NORM_QPOLYG;
8793 if(nbOfNodesExpected<1)
8795 int prevCell(0),prevNode(nodalPtr[nodalIPtr[0]+1]);
8796 *work=n2oPtr[prevNode]; work[nbOfTurn]=n2oPtr[nodalPtr[nodalIPtr[0]+3]]; work++;
8797 for(int i=1;i<nbOfTurn;i++)
8799 if(nodalIPtr[prevCell+1]-nodalIPtr[prevCell]==4)
8801 std::set<int> conn(nodalPtr+nodalIPtr[prevCell]+1,nodalPtr+nodalIPtr[prevCell]+3);
8802 conn.erase(prevNode);
8805 int curNode(*(conn.begin()));
8806 *work=n2oPtr[curNode];
8807 std::set<int> shar(revNodalPtr+revNodalIPtr[curNode],revNodalPtr+revNodalIPtr[curNode+1]);
8808 shar.erase(prevCell);
8811 int curCell(*(shar.begin()));
8812 work[nbOfTurn]=n2oPtr[nodalPtr[nodalIPtr[curCell]+3]];
8818 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected 2 !");
8821 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected 1 !");
8824 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected cell !");
8830 * This method makes the assumption spacedimension == meshdimension == 2.
8831 * This method works only for linear cells.
8833 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
8835 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMesh() const
8837 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
8838 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
8839 MCAuto<MEDCouplingUMesh> skin(computeSkin());
8840 int oldNbOfNodes(skin->getNumberOfNodes());
8841 MCAuto<DataArrayInt> o2n(skin->zipCoordsTraducer());
8842 int nbOfNodesExpected(skin->getNumberOfNodes());
8843 MCAuto<DataArrayInt> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
8844 int nbCells(skin->getNumberOfCells());
8845 if(nbCells==nbOfNodesExpected)
8846 return buildUnionOf2DMeshLinear(skin,n2o);
8847 else if(2*nbCells==nbOfNodesExpected)
8848 return buildUnionOf2DMeshQuadratic(skin,n2o);
8850 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
8854 * This method makes the assumption spacedimension == meshdimension == 3.
8855 * This method works only for linear cells.
8857 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
8859 DataArrayInt *MEDCouplingUMesh::buildUnionOf3DMesh() const
8861 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8862 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
8863 MCAuto<MEDCouplingUMesh> m=computeSkin();
8864 const int *conn=m->getNodalConnectivity()->getConstPointer();
8865 const int *connI=m->getNodalConnectivityIndex()->getConstPointer();
8866 int nbOfCells=m->getNumberOfCells();
8867 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
8868 int *work=ret->getPointer(); *work++=INTERP_KERNEL::NORM_POLYHED;
8871 work=std::copy(conn+connI[0]+1,conn+connI[1],work);
8872 for(int i=1;i<nbOfCells;i++)
8875 work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
8881 * \brief Creates a graph of cell neighbors
8882 * \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
8883 * In the sky line array, graph arcs are stored in terms of (index,value) notation.
8885 * - index: 0 3 5 6 6
8886 * - value: 1 2 3 2 3 3
8887 * means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
8888 * Arcs are not doubled but reflexive (1,1) arcs are present for each cell
8890 MEDCouplingSkyLineArray *MEDCouplingUMesh::generateGraph() const
8892 checkConnectivityFullyDefined();
8894 int meshDim = this->getMeshDimension();
8895 MEDCoupling::DataArrayInt* indexr=MEDCoupling::DataArrayInt::New();
8896 MEDCoupling::DataArrayInt* revConn=MEDCoupling::DataArrayInt::New();
8897 this->getReverseNodalConnectivity(revConn,indexr);
8898 const int* indexr_ptr=indexr->getConstPointer();
8899 const int* revConn_ptr=revConn->getConstPointer();
8901 const MEDCoupling::DataArrayInt* index;
8902 const MEDCoupling::DataArrayInt* conn;
8903 conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
8904 index=this->getNodalConnectivityIndex();
8905 int nbCells=this->getNumberOfCells();
8906 const int* index_ptr=index->getConstPointer();
8907 const int* conn_ptr=conn->getConstPointer();
8909 //creating graph arcs (cell to cell relations)
8910 //arcs are stored in terms of (index,value) notation
8913 // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
8914 // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
8916 //warning here one node have less than or equal effective number of cell with it
8917 //but cell could have more than effective nodes
8918 //because other equals nodes in other domain (with other global inode)
8919 std::vector <int> cell2cell_index(nbCells+1,0);
8920 std::vector <int> cell2cell;
8921 cell2cell.reserve(3*nbCells);
8923 for (int icell=0; icell<nbCells;icell++)
8925 std::map<int,int > counter;
8926 for (int iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
8928 int inode=conn_ptr[iconn];
8929 for (int iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
8931 int icell2=revConn_ptr[iconnr];
8932 std::map<int,int>::iterator iter=counter.find(icell2);
8933 if (iter!=counter.end()) (iter->second)++;
8934 else counter.insert(std::make_pair(icell2,1));
8937 for (std::map<int,int>::const_iterator iter=counter.begin();
8938 iter!=counter.end(); iter++)
8939 if (iter->second >= meshDim)
8941 cell2cell_index[icell+1]++;
8942 cell2cell.push_back(iter->first);
8947 cell2cell_index[0]=0;
8948 for (int icell=0; icell<nbCells;icell++)
8949 cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
8951 //filling up index and value to create skylinearray structure
8952 MEDCouplingSkyLineArray* array=new MEDCouplingSkyLineArray(cell2cell_index,cell2cell);
8957 * This method put in zip format into parameter 'zipFrmt' in full interlace mode.
8958 * This format is often asked by INTERP_KERNEL algorithms to avoid many indirections into coordinates array.
8960 void MEDCouplingUMesh::FillInCompact3DMode(int spaceDim, int nbOfNodesInCell, const int *conn, const double *coo, double *zipFrmt)
8964 for(int i=0;i<nbOfNodesInCell;i++)
8965 w=std::copy(coo+3*conn[i],coo+3*conn[i]+3,w);
8966 else if(spaceDim==2)
8968 for(int i=0;i<nbOfNodesInCell;i++)
8970 w=std::copy(coo+2*conn[i],coo+2*conn[i]+2,w);
8975 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::FillInCompact3DMode : Invalid spaceDim specified : must be 2 or 3 !");
8978 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
8980 int nbOfCells=getNumberOfCells();
8982 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
8983 ofs << " <" << getVTKDataSetType() << ">\n";
8984 ofs << " <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
8985 ofs << " <PointData>\n" << pointData << std::endl;
8986 ofs << " </PointData>\n";
8987 ofs << " <CellData>\n" << cellData << std::endl;
8988 ofs << " </CellData>\n";
8989 ofs << " <Points>\n";
8990 if(getSpaceDimension()==3)
8991 _coords->writeVTK(ofs,8,"Points",byteData);
8994 MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
8995 coo->writeVTK(ofs,8,"Points",byteData);
8997 ofs << " </Points>\n";
8998 ofs << " <Cells>\n";
8999 const int *cPtr=_nodal_connec->getConstPointer();
9000 const int *cIPtr=_nodal_connec_index->getConstPointer();
9001 MCAuto<DataArrayInt> faceoffsets=DataArrayInt::New(); faceoffsets->alloc(nbOfCells,1);
9002 MCAuto<DataArrayInt> types=DataArrayInt::New(); types->alloc(nbOfCells,1);
9003 MCAuto<DataArrayInt> offsets=DataArrayInt::New(); offsets->alloc(nbOfCells,1);
9004 MCAuto<DataArrayInt> connectivity=DataArrayInt::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
9005 int *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
9006 int szFaceOffsets=0,szConn=0;
9007 for(int i=0;i<nbOfCells;i++,w1++,w2++,w3++)
9010 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
9013 *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
9014 w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
9018 int deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
9019 *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
9020 std::set<int> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
9021 *w3=szConn+(int)c.size(); szConn+=(int)c.size();
9022 w4=std::copy(c.begin(),c.end(),w4);
9025 types->transformWithIndArr(MEDCOUPLING2VTKTYPETRADUCER,MEDCOUPLING2VTKTYPETRADUCER+INTERP_KERNEL::NORM_MAXTYPE+1);
9026 types->writeVTK(ofs,8,"UInt8","types",byteData);
9027 offsets->writeVTK(ofs,8,"Int32","offsets",byteData);
9028 if(szFaceOffsets!=0)
9029 {//presence of Polyhedra
9030 connectivity->reAlloc(szConn);
9031 faceoffsets->writeVTK(ofs,8,"Int32","faceoffsets",byteData);
9032 MCAuto<DataArrayInt> faces=DataArrayInt::New(); faces->alloc(szFaceOffsets,1);
9033 w1=faces->getPointer();
9034 for(int i=0;i<nbOfCells;i++)
9035 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
9037 int nbFaces=std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1)+1;
9039 const int *w6=cPtr+cIPtr[i]+1,*w5=0;
9040 for(int j=0;j<nbFaces;j++)
9042 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
9043 *w1++=(int)std::distance(w6,w5);
9044 w1=std::copy(w6,w5,w1);
9048 faces->writeVTK(ofs,8,"Int32","faces",byteData);
9050 connectivity->writeVTK(ofs,8,"Int32","connectivity",byteData);
9051 ofs << " </Cells>\n";
9052 ofs << " </Piece>\n";
9053 ofs << " </" << getVTKDataSetType() << ">\n";
9056 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
9058 stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
9060 { stream << " Not set !"; return ; }
9061 stream << " Mesh dimension : " << _mesh_dim << ".";
9065 { stream << " No coordinates set !"; return ; }
9066 if(!_coords->isAllocated())
9067 { stream << " Coordinates set but not allocated !"; return ; }
9068 stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
9069 stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
9070 if(!_nodal_connec_index)
9071 { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
9072 if(!_nodal_connec_index->isAllocated())
9073 { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
9074 int lgth=_nodal_connec_index->getNumberOfTuples();
9075 int cpt=_nodal_connec_index->getNumberOfComponents();
9076 if(cpt!=1 || lgth<1)
9078 stream << std::endl << "Number of cells : " << lgth-1 << ".";
9081 std::string MEDCouplingUMesh::getVTKDataSetType() const
9083 return std::string("UnstructuredGrid");
9086 std::string MEDCouplingUMesh::getVTKFileExtension() const
9088 return std::string("vtu");
9092 * Partitions the first given 2D mesh using the second given 2D mesh as a tool, and
9093 * returns a result mesh constituted by polygons.
9094 * Thus the final result contains all nodes from m1 plus new nodes. However it doesn't necessarily contains
9095 * all nodes from m2.
9096 * The meshes should be in 2D space. In
9097 * addition, returns two arrays mapping cells of the result mesh to cells of the input
9099 * \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
9100 * 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)
9101 * \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
9102 * 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)
9103 * \param [in] eps - precision used to detect coincident mesh entities.
9104 * \param [out] cellNb1 - a new instance of DataArrayInt holding for each result
9105 * cell an id of the cell of \a m1 it comes from. The caller is to delete
9106 * this array using decrRef() as it is no more needed.
9107 * \param [out] cellNb2 - a new instance of DataArrayInt holding for each result
9108 * cell an id of the cell of \a m2 it comes from. -1 value means that a
9109 * result cell comes from a cell (or part of cell) of \a m1 not overlapped by
9110 * any cell of \a m2. The caller is to delete this array using decrRef() as
9111 * it is no more needed.
9112 * \return MEDCouplingUMesh * - the result 2D mesh which is a new instance of
9113 * MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
9114 * is no more needed.
9115 * \throw If the coordinates array is not set in any of the meshes.
9116 * \throw If the nodal connectivity of cells is not defined in any of the meshes.
9117 * \throw If any of the meshes is not a 2D mesh in 2D space.
9119 * \sa conformize2D, mergeNodes
9121 MEDCouplingUMesh *MEDCouplingUMesh::Intersect2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2,
9122 double eps, DataArrayInt *&cellNb1, DataArrayInt *&cellNb2)
9125 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshes : input meshes must be not NULL !");
9126 m1->checkFullyDefined();
9127 m2->checkFullyDefined();
9128 if(m1->getMeshDimension()!=2 || m1->getSpaceDimension()!=2 || m2->getMeshDimension()!=2 || m2->getSpaceDimension()!=2)
9129 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshes works on umeshes m1 AND m2 with meshdim equal to 2 and spaceDim equal to 2 too!");
9131 // Step 1: compute all edge intersections (new nodes)
9132 std::vector< std::vector<int> > intersectEdge1, colinear2, subDiv2;
9133 MEDCouplingUMesh *m1Desc=0,*m2Desc=0; // descending connec. meshes
9134 DataArrayInt *desc1=0,*descIndx1=0,*revDesc1=0,*revDescIndx1=0,*desc2=0,*descIndx2=0,*revDesc2=0,*revDescIndx2=0;
9135 std::vector<double> addCoo,addCoordsQuadratic; // coordinates of newly created nodes
9136 IntersectDescending2DMeshes(m1,m2,eps,intersectEdge1,colinear2, subDiv2,
9137 m1Desc,desc1,descIndx1,revDesc1,revDescIndx1,
9138 addCoo, m2Desc,desc2,descIndx2,revDesc2,revDescIndx2);
9139 revDesc1->decrRef(); revDescIndx1->decrRef(); revDesc2->decrRef(); revDescIndx2->decrRef();
9140 MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(desc2),dd4(descIndx2);
9141 MCAuto<MEDCouplingUMesh> dd5(m1Desc),dd6(m2Desc);
9143 // Step 2: re-order newly created nodes according to the ordering found in m2
9144 std::vector< std::vector<int> > intersectEdge2;
9145 BuildIntersectEdges(m1Desc,m2Desc,addCoo,subDiv2,intersectEdge2);
9146 subDiv2.clear(); dd5=0; dd6=0;
9149 std::vector<int> cr,crI; //no DataArrayInt because interface with Geometric2D
9150 std::vector<int> cNb1,cNb2; //no DataArrayInt because interface with Geometric2D
9151 BuildIntersecting2DCellsFromEdges(eps,m1,desc1->getConstPointer(),descIndx1->getConstPointer(),intersectEdge1,colinear2,m2,desc2->getConstPointer(),descIndx2->getConstPointer(),intersectEdge2,addCoo,
9152 /* outputs -> */addCoordsQuadratic,cr,crI,cNb1,cNb2);
9154 // Step 4: Prepare final result:
9155 MCAuto<DataArrayDouble> addCooDa(DataArrayDouble::New());
9156 addCooDa->alloc((int)(addCoo.size())/2,2);
9157 std::copy(addCoo.begin(),addCoo.end(),addCooDa->getPointer());
9158 MCAuto<DataArrayDouble> addCoordsQuadraticDa(DataArrayDouble::New());
9159 addCoordsQuadraticDa->alloc((int)(addCoordsQuadratic.size())/2,2);
9160 std::copy(addCoordsQuadratic.begin(),addCoordsQuadratic.end(),addCoordsQuadraticDa->getPointer());
9161 std::vector<const DataArrayDouble *> coordss(4);
9162 coordss[0]=m1->getCoords(); coordss[1]=m2->getCoords(); coordss[2]=addCooDa; coordss[3]=addCoordsQuadraticDa;
9163 MCAuto<DataArrayDouble> coo(DataArrayDouble::Aggregate(coordss));
9164 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("Intersect2D",2));
9165 MCAuto<DataArrayInt> conn(DataArrayInt::New()); conn->alloc((int)cr.size(),1); std::copy(cr.begin(),cr.end(),conn->getPointer());
9166 MCAuto<DataArrayInt> connI(DataArrayInt::New()); connI->alloc((int)crI.size(),1); std::copy(crI.begin(),crI.end(),connI->getPointer());
9167 MCAuto<DataArrayInt> c1(DataArrayInt::New()); c1->alloc((int)cNb1.size(),1); std::copy(cNb1.begin(),cNb1.end(),c1->getPointer());
9168 MCAuto<DataArrayInt> c2(DataArrayInt::New()); c2->alloc((int)cNb2.size(),1); std::copy(cNb2.begin(),cNb2.end(),c2->getPointer());
9169 ret->setConnectivity(conn,connI,true);
9170 ret->setCoords(coo);
9171 cellNb1=c1.retn(); cellNb2=c2.retn();
9177 bool IsColinearOfACellOf(const std::vector< std::vector<int> >& intersectEdge1, const std::vector<int>& candidates, int start, int stop, int& retVal)
9179 if(candidates.empty())
9181 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
9183 const std::vector<int>& pool(intersectEdge1[*it]);
9184 int tmp[2]; tmp[0]=start; tmp[1]=stop;
9185 if(std::search(pool.begin(),pool.end(),tmp,tmp+2)!=pool.end())
9190 tmp[0]=stop; tmp[1]=start;
9191 if(std::search(pool.begin(),pool.end(),tmp,tmp+2)!=pool.end())
9200 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,
9201 MCAuto<DataArrayInt>& idsInRetColinear, MCAuto<DataArrayInt>& idsInMesh1DForIdsInRetColinear)
9203 idsInRetColinear=DataArrayInt::New(); idsInRetColinear->alloc(0,1);
9204 idsInMesh1DForIdsInRetColinear=DataArrayInt::New(); idsInMesh1DForIdsInRetColinear->alloc(0,1);
9205 int nCells(mesh1D->getNumberOfCells());
9206 if(nCells!=(int)intersectEdge2.size())
9207 throw INTERP_KERNEL::Exception("BuildMesh1DCutFrom : internal error # 1 !");
9208 const DataArrayDouble *coo2(mesh1D->getCoords());
9209 const int *c(mesh1D->getNodalConnectivity()->begin()),*ci(mesh1D->getNodalConnectivityIndex()->begin());
9210 const double *coo2Ptr(coo2->begin());
9211 int offset1(coords1->getNumberOfTuples());
9212 int offset2(offset1+coo2->getNumberOfTuples());
9213 int offset3(offset2+addCoo.size()/2);
9214 std::vector<double> addCooQuad;
9215 MCAuto<DataArrayInt> cOut(DataArrayInt::New()),ciOut(DataArrayInt::New()); cOut->alloc(0,1); ciOut->alloc(1,1); ciOut->setIJ(0,0,0);
9216 int tmp[4],cicnt(0),kk(0);
9217 for(int i=0;i<nCells;i++)
9219 std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
9220 INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coo2Ptr,m));
9221 const std::vector<int>& subEdges(intersectEdge2[i]);
9222 int nbSubEdge(subEdges.size()/2);
9223 for(int j=0;j<nbSubEdge;j++,kk++)
9225 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));
9226 MCAuto<INTERP_KERNEL::Edge> e2(e->buildEdgeLyingOnMe(n1,n2));
9227 INTERP_KERNEL::Edge *e2Ptr(e2);
9228 std::map<int,int>::const_iterator itm;
9229 if(dynamic_cast<INTERP_KERNEL::EdgeArcCircle *>(e2Ptr))
9231 tmp[0]=INTERP_KERNEL::NORM_SEG3;
9232 itm=mergedNodes.find(subEdges[2*j]);
9233 tmp[1]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j];
9234 itm=mergedNodes.find(subEdges[2*j+1]);
9235 tmp[2]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j+1];
9236 tmp[3]=offset3+(int)addCooQuad.size()/2;
9238 e2->getBarycenter(tmp2); addCooQuad.insert(addCooQuad.end(),tmp2,tmp2+2);
9240 cOut->insertAtTheEnd(tmp,tmp+4);
9241 ciOut->pushBackSilent(cicnt);
9245 tmp[0]=INTERP_KERNEL::NORM_SEG2;
9246 itm=mergedNodes.find(subEdges[2*j]);
9247 tmp[1]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j];
9248 itm=mergedNodes.find(subEdges[2*j+1]);
9249 tmp[2]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j+1];
9251 cOut->insertAtTheEnd(tmp,tmp+3);
9252 ciOut->pushBackSilent(cicnt);
9255 if(IsColinearOfACellOf(intersectEdge1,colinear2[i],tmp[1],tmp[2],tmp00))
9257 idsInRetColinear->pushBackSilent(kk);
9258 idsInMesh1DForIdsInRetColinear->pushBackSilent(tmp00);
9263 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(mesh1D->getName(),1));
9264 ret->setConnectivity(cOut,ciOut,true);
9265 MCAuto<DataArrayDouble> arr3(DataArrayDouble::New());
9266 arr3->useArray(&addCoo[0],false,C_DEALLOC,(int)addCoo.size()/2,2);
9267 MCAuto<DataArrayDouble> arr4(DataArrayDouble::New()); arr4->useArray(&addCooQuad[0],false,C_DEALLOC,(int)addCooQuad.size()/2,2);
9268 std::vector<const DataArrayDouble *> coordss(4);
9269 coordss[0]=coords1; coordss[1]=mesh1D->getCoords(); coordss[2]=arr3; coordss[3]=arr4;
9270 MCAuto<DataArrayDouble> arr(DataArrayDouble::Aggregate(coordss));
9271 ret->setCoords(arr);
9275 MEDCouplingUMesh *BuildRefined2DCellLinear(const DataArrayDouble *coords, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9277 std::vector<int> allEdges;
9278 for(const int *it2(descBg);it2!=descEnd;it2++)
9280 const std::vector<int>& edge1(intersectEdge1[std::abs(*it2)-1]);
9282 allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9284 allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9286 std::size_t nb(allEdges.size());
9288 throw INTERP_KERNEL::Exception("BuildRefined2DCellLinear : internal error 1 !");
9289 std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9290 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
9291 ret->setCoords(coords);
9292 ret->allocateCells(1);
9293 std::vector<int> connOut(nbOfEdgesOf2DCellSplit);
9294 for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9295 connOut[kk]=allEdges[2*kk];
9296 ret->insertNextCell(INTERP_KERNEL::NORM_POLYGON,connOut.size(),&connOut[0]);
9300 MEDCouplingUMesh *BuildRefined2DCellQuadratic(const DataArrayDouble *coords, const MEDCouplingUMesh *mesh2D, int cellIdInMesh2D, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9302 const int *c(mesh2D->getNodalConnectivity()->begin()),*ci(mesh2D->getNodalConnectivityIndex()->begin());
9303 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[cellIdInMesh2D]]));
9305 unsigned sz(cm.getNumberOfSons2(c+ci[cellIdInMesh2D]+1,ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]-1));
9306 if(sz!=std::distance(descBg,descEnd))
9307 throw INTERP_KERNEL::Exception("BuildRefined2DCellQuadratic : internal error 1 !");
9308 INTERP_KERNEL::AutoPtr<int> tmpPtr(new int[ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]]);
9309 std::vector<int> allEdges,centers;
9310 const double *coordsPtr(coords->begin());
9311 MCAuto<DataArrayDouble> addCoo(DataArrayDouble::New()); addCoo->alloc(0,1);
9312 int offset(coords->getNumberOfTuples());
9313 for(const int *it2(descBg);it2!=descEnd;it2++,ii++)
9315 INTERP_KERNEL::NormalizedCellType typeOfSon;
9316 cm.fillSonCellNodalConnectivity2(ii,c+ci[cellIdInMesh2D]+1,ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]-1,tmpPtr,typeOfSon);
9317 const std::vector<int>& edge1(intersectEdge1[std::abs(*it2)-1]);
9319 allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9321 allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9323 centers.push_back(tmpPtr[2]);//special case where no subsplit of edge -> reuse the original center.
9325 {//the current edge has been subsplit -> create corresponding centers.
9326 std::size_t nbOfCentersToAppend(edge1.size()/2);
9327 std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9328 MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpPtr,coordsPtr,m));
9329 std::vector<int>::const_iterator it3(allEdges.end()-edge1.size());
9330 for(std::size_t k=0;k<nbOfCentersToAppend;k++)
9333 const double *aa(coordsPtr+2*(*it3++));
9334 const double *bb(coordsPtr+2*(*it3++));
9335 ee->getMiddleOfPoints(aa,bb,tmpp);
9336 addCoo->insertAtTheEnd(tmpp,tmpp+2);
9337 centers.push_back(offset+k);
9341 std::size_t nb(allEdges.size());
9343 throw INTERP_KERNEL::Exception("BuildRefined2DCellQuadratic : internal error 2 !");
9344 std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9345 MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
9347 ret->setCoords(coords);
9350 addCoo->rearrange(2);
9351 addCoo=DataArrayDouble::Aggregate(coords,addCoo);
9352 ret->setCoords(addCoo);
9354 ret->allocateCells(1);
9355 std::vector<int> connOut(nbOfEdgesOf2DCellSplit);
9356 for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9357 connOut[kk]=allEdges[2*kk];
9358 connOut.insert(connOut.end(),centers.begin(),centers.end());
9359 ret->insertNextCell(INTERP_KERNEL::NORM_QPOLYG,connOut.size(),&connOut[0]);
9364 * This method creates a refinement of a cell in \a mesh2D. Those cell is defined by descending connectivity and the sorted subdivided nodal connectivity
9367 * \param [in] mesh2D - The origin 2D mesh. \b Warning \b coords are not those of \a mesh2D. But mesh2D->getCoords()==coords[:mesh2D->getNumberOfNodes()]
9369 MEDCouplingUMesh *BuildRefined2DCell(const DataArrayDouble *coords, const MEDCouplingUMesh *mesh2D, int cellIdInMesh2D, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9371 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(mesh2D->getTypeOfCell(cellIdInMesh2D)));
9372 if(!cm.isQuadratic())
9373 return BuildRefined2DCellLinear(coords,descBg,descEnd,intersectEdge1);
9375 return BuildRefined2DCellQuadratic(coords,mesh2D,cellIdInMesh2D,descBg,descEnd,intersectEdge1);
9378 void AddCellInMesh2D(MEDCouplingUMesh *mesh2D, const std::vector<int>& conn, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edges)
9381 for(std::vector< MCAuto<INTERP_KERNEL::Edge> >::const_iterator it=edges.begin();it!=edges.end();it++)
9383 const INTERP_KERNEL::Edge *ee(*it);
9384 if(dynamic_cast<const INTERP_KERNEL::EdgeArcCircle *>(ee))
9388 mesh2D->insertNextCell(INTERP_KERNEL::NORM_POLYGON,conn.size(),&conn[0]);
9391 const double *coo(mesh2D->getCoords()->begin());
9392 std::size_t sz(conn.size());
9393 std::vector<double> addCoo;
9394 std::vector<int> conn2(conn);
9395 int offset(mesh2D->getNumberOfNodes());
9396 for(std::size_t i=0;i<sz;i++)
9399 edges[(i+1)%sz]->getMiddleOfPoints(coo+2*conn[i],coo+2*conn[(i+1)%sz],tmp);// tony a chier i+1 -> i
9400 addCoo.insert(addCoo.end(),tmp,tmp+2);
9401 conn2.push_back(offset+(int)i);
9403 mesh2D->getCoords()->rearrange(1);
9404 mesh2D->getCoords()->pushBackValsSilent(&addCoo[0],&addCoo[0]+addCoo.size());
9405 mesh2D->getCoords()->rearrange(2);
9406 mesh2D->insertNextCell(INTERP_KERNEL::NORM_QPOLYG,conn2.size(),&conn2[0]);
9411 * \b WARNING edges in out1 coming from \a splitMesh1D are \b NOT oriented because only used for equation of curve.
9413 * This method cuts in 2 parts the input 2D cell given using boundaries description (\a edge1Bis and \a edge1BisPtr) using
9414 * a set of edges defined in \a splitMesh1D.
9416 void BuildMesh2DCutInternal2(const MEDCouplingUMesh *splitMesh1D, const std::vector<int>& edge1Bis, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edge1BisPtr,
9417 std::vector< std::vector<int> >& out0, std::vector< std::vector< MCAuto<INTERP_KERNEL::Edge> > >& out1)
9419 std::size_t nb(edge1Bis.size()/2);
9420 std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9421 int iEnd(splitMesh1D->getNumberOfCells());
9423 throw INTERP_KERNEL::Exception("BuildMesh2DCutInternal2 : internal error ! input 1D mesh must have at least one cell !");
9425 const int *cSplitPtr(splitMesh1D->getNodalConnectivity()->begin()),*ciSplitPtr(splitMesh1D->getNodalConnectivityIndex()->begin());
9426 for(ii=0;ii<nb && edge1Bis[2*ii]!=cSplitPtr[ciSplitPtr[0]+1];ii++);
9427 for(jj=ii;jj<nb && edge1Bis[2*jj+1]!=cSplitPtr[ciSplitPtr[iEnd-1]+2];jj++);
9430 {//the edges splitMesh1D[iStart:iEnd] does not fully cut the current 2D cell -> single output cell
9431 out0.resize(1); out1.resize(1);
9432 std::vector<int>& connOut(out0[0]);
9433 connOut.resize(nbOfEdgesOf2DCellSplit);
9434 std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr(out1[0]);
9435 edgesPtr.resize(nbOfEdgesOf2DCellSplit);
9436 for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9438 connOut[kk]=edge1Bis[2*kk];
9439 edgesPtr[kk]=edge1BisPtr[2*kk];
9444 // [i,iEnd[ contains the
9445 out0.resize(2); out1.resize(2);
9446 std::vector<int>& connOutLeft(out0[0]);
9447 std::vector<int>& connOutRight(out0[1]);//connOutLeft should end with edge1Bis[2*ii] and connOutRight should end with edge1Bis[2*jj+1]
9448 std::vector< MCAuto<INTERP_KERNEL::Edge> >& eleft(out1[0]);
9449 std::vector< MCAuto<INTERP_KERNEL::Edge> >& eright(out1[1]);
9450 for(std::size_t k=ii;k<jj+1;k++)
9451 { connOutLeft.push_back(edge1Bis[2*k+1]); eleft.push_back(edge1BisPtr[2*k+1]); }
9452 std::vector< MCAuto<INTERP_KERNEL::Edge> > ees(iEnd);
9453 for(int ik=0;ik<iEnd;ik++)
9455 std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9456 MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)cSplitPtr[ciSplitPtr[ik]],cSplitPtr+ciSplitPtr[ik]+1,splitMesh1D->getCoords()->begin(),m));
9459 for(int ik=iEnd-1;ik>=0;ik--)
9460 connOutLeft.push_back(cSplitPtr[ciSplitPtr[ik]+1]);
9461 for(std::size_t k=jj+1;k<nbOfEdgesOf2DCellSplit+ii;k++)
9462 { connOutRight.push_back(edge1Bis[2*k+1]); eright.push_back(edge1BisPtr[2*k+1]); }
9463 eleft.insert(eleft.end(),ees.rbegin(),ees.rend());
9464 for(int ik=0;ik<iEnd;ik++)
9465 connOutRight.push_back(cSplitPtr[ciSplitPtr[ik]+2]);
9466 eright.insert(eright.end(),ees.begin(),ees.end());
9478 CellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr);
9480 std::vector<int> _edges;
9481 std::vector< MCAuto<INTERP_KERNEL::Edge> > _edges_ptr;
9484 CellInfo::CellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr)
9486 std::size_t nbe(edges.size());
9487 std::vector<int> edges2(2*nbe); std::vector< MCAuto<INTERP_KERNEL::Edge> > edgesPtr2(2*nbe);
9488 for(std::size_t i=0;i<nbe;i++)
9490 edges2[2*i]=edges[i]; edges2[2*i+1]=edges[(i+1)%nbe];
9491 edgesPtr2[2*i]=edgesPtr[(i+1)%nbe]; edgesPtr2[2*i+1]=edgesPtr[(i+1)%nbe];//tony a chier
9493 _edges.resize(4*nbe); _edges_ptr.resize(4*nbe);
9494 std::copy(edges2.begin(),edges2.end(),_edges.begin()); std::copy(edges2.begin(),edges2.end(),_edges.begin()+2*nbe);
9495 std::copy(edgesPtr2.begin(),edgesPtr2.end(),_edges_ptr.begin()); std::copy(edgesPtr2.begin(),edgesPtr2.end(),_edges_ptr.begin()+2*nbe);
9501 EdgeInfo(int istart, int iend, const MCAuto<MEDCouplingUMesh>& mesh):_istart(istart),_iend(iend),_mesh(mesh),_left(-7),_right(-7) { }
9502 EdgeInfo(int istart, int iend, int pos, const MCAuto<INTERP_KERNEL::Edge>& edge):_istart(istart),_iend(iend),_edge(edge),_left(pos),_right(pos+1) { }
9503 bool isInMyRange(int pos) const { return pos>=_istart && pos<_iend; }
9504 void somethingHappendAt(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight);
9505 void feedEdgeInfoAt(double eps, const MEDCouplingUMesh *mesh2D, int offset, int neighbors[2]) const;
9509 MCAuto<MEDCouplingUMesh> _mesh;
9510 MCAuto<INTERP_KERNEL::Edge> _edge;
9515 void EdgeInfo::somethingHappendAt(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight)
9517 const MEDCouplingUMesh *mesh(_mesh);
9523 { _left++; _right++; return ; }
9526 bool isLeft(std::find(newLeft.begin(),newLeft.end(),_edge)!=newLeft.end()),isRight(std::find(newRight.begin(),newRight.end(),_edge)!=newRight.end());
9527 if((isLeft && isRight) || (!isLeft && !isRight))
9528 throw INTERP_KERNEL::Exception("EdgeInfo::somethingHappendAt : internal error # 1 !");
9539 bool isLeft(std::find(newLeft.begin(),newLeft.end(),_edge)!=newLeft.end()),isRight(std::find(newRight.begin(),newRight.end(),_edge)!=newRight.end());
9540 if((isLeft && isRight) || (!isLeft && !isRight))
9541 throw INTERP_KERNEL::Exception("EdgeInfo::somethingHappendAt : internal error # 2 !");
9556 void EdgeInfo::feedEdgeInfoAt(double eps, const MEDCouplingUMesh *mesh2D, int offset, int neighbors[2]) const
9558 const MEDCouplingUMesh *mesh(_mesh);
9561 neighbors[0]=offset+_left; neighbors[1]=offset+_right;
9564 {// not fully splitting cell case
9565 if(mesh2D->getNumberOfCells()==1)
9566 {//little optimization. 1 cell no need to find in which cell mesh is !
9567 neighbors[0]=offset; neighbors[1]=offset;
9572 MCAuto<DataArrayDouble> barys(mesh->computeCellCenterOfMass());
9573 int cellId(mesh2D->getCellContainingPoint(barys->begin(),eps));
9575 throw INTERP_KERNEL::Exception("EdgeInfo::feedEdgeInfoAt : internal error !");
9576 neighbors[0]=offset+cellId; neighbors[1]=offset+cellId;
9581 class VectorOfCellInfo
9584 VectorOfCellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr);
9585 std::size_t size() const { return _pool.size(); }
9586 int getPositionOf(double eps, const MEDCouplingUMesh *mesh) const;
9587 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);
9588 const std::vector<int>& getConnOf(int pos) const { return get(pos)._edges; }
9589 const std::vector< MCAuto<INTERP_KERNEL::Edge> >& getEdgePtrOf(int pos) const { return get(pos)._edges_ptr; }
9590 MCAuto<MEDCouplingUMesh> getZeMesh() const { return _ze_mesh; }
9591 void feedEdgeInfoAt(double eps, int pos, int offset, int neighbors[2]) const;
9593 int getZePosOfEdgeGivenItsGlobalId(int pos) const;
9594 void updateEdgeInfo(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight);
9595 const CellInfo& get(int pos) const;
9596 CellInfo& get(int pos);
9598 std::vector<CellInfo> _pool;
9599 MCAuto<MEDCouplingUMesh> _ze_mesh;
9600 std::vector<EdgeInfo> _edge_info;
9603 VectorOfCellInfo::VectorOfCellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr):_pool(1)
9605 _pool[0]._edges=edges;
9606 _pool[0]._edges_ptr=edgesPtr;
9609 int VectorOfCellInfo::getPositionOf(double eps, const MEDCouplingUMesh *mesh) const
9612 throw INTERP_KERNEL::Exception("VectorOfCellSplitter::getPositionOf : empty !");
9615 const MEDCouplingUMesh *zeMesh(_ze_mesh);
9617 throw INTERP_KERNEL::Exception("VectorOfCellSplitter::getPositionOf : null aggregated mesh !");
9618 MCAuto<DataArrayDouble> barys(mesh->computeCellCenterOfMass());
9619 return zeMesh->getCellContainingPoint(barys->begin(),eps);
9622 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)
9624 get(pos);//to check pos
9625 bool isFast(pos==0 && _pool.size()==1);
9626 std::size_t sz(edges.size());
9627 // dealing with edges
9629 _edge_info.push_back(EdgeInfo(istart,iend,mesh1DInCase));
9631 _edge_info.push_back(EdgeInfo(istart,iend,pos,edgePtrs[0].back()));
9633 std::vector<CellInfo> pool(_pool.size()-1+sz);
9634 for(int i=0;i<pos;i++)
9636 for(std::size_t j=0;j<sz;j++)
9637 pool[pos+j]=CellInfo(edges[j],edgePtrs[j]);
9638 for(int i=pos+1;i<(int)_pool.size();i++)
9639 pool[i+sz-1]=_pool[i];
9643 updateEdgeInfo(pos,edgePtrs[0],edgePtrs[1]);
9651 std::vector< MCAuto<MEDCouplingUMesh> > ms;
9654 MCAuto<MEDCouplingUMesh> elt(static_cast<MEDCouplingUMesh *>(_ze_mesh->buildPartOfMySelfSlice(0,pos,true)));
9658 if(pos<_ze_mesh->getNumberOfCells()-1)
9660 MCAuto<MEDCouplingUMesh> elt(static_cast<MEDCouplingUMesh *>(_ze_mesh->buildPartOfMySelfSlice(pos+1,_ze_mesh->getNumberOfCells(),true)));
9663 std::vector< const MEDCouplingUMesh *> ms2(ms.size());
9664 for(std::size_t j=0;j<ms2.size();j++)
9666 _ze_mesh=MEDCouplingUMesh::MergeUMeshesOnSameCoords(ms2);
9669 void VectorOfCellInfo::feedEdgeInfoAt(double eps, int pos, int offset, int neighbors[2]) const
9671 _edge_info[getZePosOfEdgeGivenItsGlobalId(pos)].feedEdgeInfoAt(eps,_ze_mesh,offset,neighbors);
9674 int VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId(int pos) const
9677 throw INTERP_KERNEL::Exception("VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId : invalid id ! Must be >=0 !");
9679 for(std::vector<EdgeInfo>::const_iterator it=_edge_info.begin();it!=_edge_info.end();it++,ret++)
9681 if((*it).isInMyRange(pos))
9684 throw INTERP_KERNEL::Exception("VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId : invalid id !");
9687 void VectorOfCellInfo::updateEdgeInfo(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight)
9689 get(pos);//to check;
9690 if(_edge_info.empty())
9692 std::size_t sz(_edge_info.size()-1);
9693 for(std::size_t i=0;i<sz;i++)
9694 _edge_info[i].somethingHappendAt(pos,newLeft,newRight);
9697 const CellInfo& VectorOfCellInfo::get(int pos) const
9699 if(pos<0 || pos>=(int)_pool.size())
9700 throw INTERP_KERNEL::Exception("VectorOfCellSplitter::get const : invalid pos !");
9704 CellInfo& VectorOfCellInfo::get(int pos)
9706 if(pos<0 || pos>=(int)_pool.size())
9707 throw INTERP_KERNEL::Exception("VectorOfCellSplitter::get : invalid pos !");
9713 * - a \b closed set of edges ( \a allEdges and \a allEdgesPtr ) that defines the split descending 2D cell.
9714 * - \a splitMesh1D a split 2D curve mesh contained into 2D cell defined above.
9716 * This method returns the 2D mesh and feeds \a idsLeftRight using offset.
9718 * Algorithm : \a splitMesh1D is cut into contiguous parts. Each contiguous parts will build incrementally the output 2D cells.
9720 * \param [in] allEdges a list of pairs (beginNode, endNode). Linked with \a allEdgesPtr to get the equation of edge.
9722 MEDCouplingUMesh *BuildMesh2DCutInternal(double eps, const MEDCouplingUMesh *splitMesh1D, const std::vector<int>& allEdges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& allEdgesPtr, int offset,
9723 MCAuto<DataArrayInt>& idsLeftRight)
9725 int nbCellsInSplitMesh1D(splitMesh1D->getNumberOfCells());
9726 if(nbCellsInSplitMesh1D==0)
9727 throw INTERP_KERNEL::Exception("BuildMesh2DCutInternal : internal error ! input 1D mesh must have at least one cell !");
9728 const int *cSplitPtr(splitMesh1D->getNodalConnectivity()->begin()),*ciSplitPtr(splitMesh1D->getNodalConnectivityIndex()->begin());
9729 std::size_t nb(allEdges.size()),jj;
9731 throw INTERP_KERNEL::Exception("BuildMesh2DCutFrom : internal error 2 !");
9732 std::vector<int> edge1Bis(nb*2);
9733 std::vector< MCAuto<INTERP_KERNEL::Edge> > edge1BisPtr(nb*2);
9734 std::copy(allEdges.begin(),allEdges.end(),edge1Bis.begin());
9735 std::copy(allEdges.begin(),allEdges.end(),edge1Bis.begin()+nb);
9736 std::copy(allEdgesPtr.begin(),allEdgesPtr.end(),edge1BisPtr.begin());
9737 std::copy(allEdgesPtr.begin(),allEdgesPtr.end(),edge1BisPtr.begin()+nb);
9739 idsLeftRight=DataArrayInt::New(); idsLeftRight->alloc(nbCellsInSplitMesh1D*2); idsLeftRight->fillWithValue(-2); idsLeftRight->rearrange(2);
9740 int *idsLeftRightPtr(idsLeftRight->getPointer());
9741 VectorOfCellInfo pool(edge1Bis,edge1BisPtr);
9742 for(int iStart=0;iStart<nbCellsInSplitMesh1D;)
9743 {// split [0:nbCellsInSplitMesh1D) in contiguous parts [iStart:iEnd)
9745 for(;iEnd<nbCellsInSplitMesh1D;)
9747 for(jj=0;jj<nb && edge1Bis[2*jj+1]!=cSplitPtr[ciSplitPtr[iEnd]+2];jj++);
9753 if(iEnd<nbCellsInSplitMesh1D)
9756 MCAuto<MEDCouplingUMesh> partOfSplitMesh1D(static_cast<MEDCouplingUMesh *>(splitMesh1D->buildPartOfMySelfSlice(iStart,iEnd,1,true)));
9757 int pos(pool.getPositionOf(eps,partOfSplitMesh1D));
9759 MCAuto<MEDCouplingUMesh>retTmp(MEDCouplingUMesh::New("",2));
9760 retTmp->setCoords(splitMesh1D->getCoords());
9761 retTmp->allocateCells();
9763 std::vector< std::vector<int> > out0;
9764 std::vector< std::vector< MCAuto<INTERP_KERNEL::Edge> > > out1;
9766 BuildMesh2DCutInternal2(partOfSplitMesh1D,pool.getConnOf(pos),pool.getEdgePtrOf(pos),out0,out1);
9767 for(std::size_t cnt=0;cnt<out0.size();cnt++)
9768 AddCellInMesh2D(retTmp,out0[cnt],out1[cnt]);
9769 pool.setMeshAt(pos,retTmp,iStart,iEnd,partOfSplitMesh1D,out0,out1);
9773 for(int mm=0;mm<nbCellsInSplitMesh1D;mm++)
9774 pool.feedEdgeInfoAt(eps,mm,offset,idsLeftRightPtr+2*mm);
9775 return pool.getZeMesh().retn();
9778 MEDCouplingUMesh *BuildMesh2DCutFrom(double eps, int cellIdInMesh2D, const MEDCouplingUMesh *mesh2DDesc, const MEDCouplingUMesh *splitMesh1D,
9779 const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1, int offset,
9780 MCAuto<DataArrayInt>& idsLeftRight)
9782 const int *cdescPtr(mesh2DDesc->getNodalConnectivity()->begin()),*cidescPtr(mesh2DDesc->getNodalConnectivityIndex()->begin());
9784 std::vector<int> allEdges;
9785 std::vector< MCAuto<INTERP_KERNEL::Edge> > allEdgesPtr; // for each sub edge in splitMesh2D the uncut Edge object of the original mesh2D
9786 for(const int *it(descBg);it!=descEnd;it++) // for all edges in the descending connectivity of the 2D mesh in relative Fortran mode
9788 int edgeId(std::abs(*it)-1);
9789 std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9790 MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)cdescPtr[cidescPtr[edgeId]],cdescPtr+cidescPtr[edgeId]+1,mesh2DDesc->getCoords()->begin(),m));
9791 const std::vector<int>& edge1(intersectEdge1[edgeId]);
9793 allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9795 allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9796 std::size_t sz(edge1.size());
9797 for(std::size_t cnt=0;cnt<sz;cnt++)
9798 allEdgesPtr.push_back(ee);
9801 return BuildMesh2DCutInternal(eps,splitMesh1D,allEdges,allEdgesPtr,offset,idsLeftRight);
9804 bool AreEdgeEqual(const double *coo2D, const INTERP_KERNEL::CellModel& typ1, const int *conn1, const INTERP_KERNEL::CellModel& typ2, const int *conn2, double eps)
9806 if(!typ1.isQuadratic() && !typ2.isQuadratic())
9807 {//easy case comparison not
9808 return conn1[0]==conn2[0] && conn1[1]==conn2[1];
9810 else if(typ1.isQuadratic() && typ2.isQuadratic())
9812 bool status0(conn1[0]==conn2[0] && conn1[1]==conn2[1]);
9815 if(conn1[2]==conn2[2])
9817 const double *a(coo2D+2*conn1[2]),*b(coo2D+2*conn2[2]);
9818 double dist(sqrt((a[0]-b[0])*(a[0]-b[0])+(a[1]-b[1])*(a[1]-b[1])));
9822 {//only one is quadratic
9823 bool status0(conn1[0]==conn2[0] && conn1[1]==conn2[1]);
9826 const double *a(0),*bb(0),*be(0);
9827 if(typ1.isQuadratic())
9829 a=coo2D+2*conn1[2]; bb=coo2D+2*conn2[0]; be=coo2D+2*conn2[1];
9833 a=coo2D+2*conn2[2]; bb=coo2D+2*conn1[0]; be=coo2D+2*conn1[1];
9835 double b[2]; b[0]=(be[0]+bb[0])/2.; b[1]=(be[1]+bb[1])/2.;
9836 double dist(sqrt((a[0]-b[0])*(a[0]-b[0])+(a[1]-b[1])*(a[1]-b[1])));
9842 * This method returns among the cellIds [ \a candidatesIn2DBg , \a candidatesIn2DEnd ) in \a mesh2DSplit those exactly sharing \a cellIdInMesh1DSplitRelative in \a mesh1DSplit.
9843 * \a mesh2DSplit and \a mesh1DSplit are expected to share the coordinates array.
9845 * \param [in] cellIdInMesh1DSplitRelative is in Fortran mode using sign to specify direction.
9847 int FindRightCandidateAmong(const MEDCouplingUMesh *mesh2DSplit, const int *candidatesIn2DBg, const int *candidatesIn2DEnd, const MEDCouplingUMesh *mesh1DSplit, int cellIdInMesh1DSplitRelative, double eps)
9849 if(candidatesIn2DEnd==candidatesIn2DBg)
9850 throw INTERP_KERNEL::Exception("FindRightCandidateAmong : internal error 1 !");
9851 const double *coo(mesh2DSplit->getCoords()->begin());
9852 if(std::distance(candidatesIn2DBg,candidatesIn2DEnd)==1)
9853 return *candidatesIn2DBg;
9854 int edgeId(std::abs(cellIdInMesh1DSplitRelative)-1);
9855 MCAuto<MEDCouplingUMesh> cur1D(static_cast<MEDCouplingUMesh *>(mesh1DSplit->buildPartOfMySelf(&edgeId,&edgeId+1,true)));
9856 if(cellIdInMesh1DSplitRelative<0)
9857 cur1D->changeOrientationOfCells();
9858 const int *c1D(cur1D->getNodalConnectivity()->begin());
9859 const INTERP_KERNEL::CellModel& ref1DType(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c1D[0]));
9860 for(const int *it=candidatesIn2DBg;it!=candidatesIn2DEnd;it++)
9862 MCAuto<MEDCouplingUMesh> cur2D(static_cast<MEDCouplingUMesh *>(mesh2DSplit->buildPartOfMySelf(it,it+1,true)));
9863 const int *c(cur2D->getNodalConnectivity()->begin()),*ci(cur2D->getNodalConnectivityIndex()->begin());
9864 const INTERP_KERNEL::CellModel &cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[0]]));
9865 unsigned sz(cm.getNumberOfSons2(c+ci[0]+1,ci[1]-ci[0]-1));
9866 INTERP_KERNEL::AutoPtr<int> tmpPtr(new int[ci[1]-ci[0]]);
9867 for(unsigned it2=0;it2<sz;it2++)
9869 INTERP_KERNEL::NormalizedCellType typeOfSon;
9870 cm.fillSonCellNodalConnectivity2(it2,c+ci[0]+1,ci[1]-ci[0]-1,tmpPtr,typeOfSon);
9871 const INTERP_KERNEL::CellModel &curCM(INTERP_KERNEL::CellModel::GetCellModel(typeOfSon));
9872 if(AreEdgeEqual(coo,ref1DType,c1D+1,curCM,tmpPtr,eps))
9876 throw INTERP_KERNEL::Exception("FindRightCandidateAmong : internal error 2 ! Unable to find the edge among split cell !");
9882 * Partitions the first given 2D mesh using the second given 1D mesh as a tool.
9883 * 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
9884 * and finaly, in case of quadratic polygon the centers of edges new nodes.
9885 * The meshes should be in 2D space. In addition, returns two arrays mapping cells of the resulting mesh to cells of the input.
9887 * \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
9888 * 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)
9889 * \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
9890 * you can invoke orderConsecutiveCells1D on \a mesh1D.
9891 * \param [in] eps - precision used to perform intersections and localization operations.
9892 * \param [out] splitMesh2D - the result of the split of \a mesh2D mesh.
9893 * \param [out] splitMesh1D - the result of the split of \a mesh1D mesh.
9894 * \param [out] cellIdInMesh2D - the array that gives for each cell id \a i in \a splitMesh2D the id in \a mesh2D it comes from.
9895 * 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.
9896 * \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
9897 * and the cell in \a splitMesh2D on the right for the 2nt component. -1 means no cell.
9898 * 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.
9900 * \sa Intersect2DMeshes, orderConsecutiveCells1D, conformize2D, mergeNodes
9902 void MEDCouplingUMesh::Intersect2DMeshWith1DLine(const MEDCouplingUMesh *mesh2D, const MEDCouplingUMesh *mesh1D, double eps, MEDCouplingUMesh *&splitMesh2D, MEDCouplingUMesh *&splitMesh1D, DataArrayInt *&cellIdInMesh2D, DataArrayInt *&cellIdInMesh1D)
9904 if(!mesh2D || !mesh1D)
9905 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshWith1DLine : input meshes must be not NULL !");
9906 mesh2D->checkFullyDefined();
9907 mesh1D->checkFullyDefined();
9908 const std::vector<std::string>& compNames(mesh2D->getCoords()->getInfoOnComponents());
9909 if(mesh2D->getMeshDimension()!=2 || mesh2D->getSpaceDimension()!=2 || mesh1D->getMeshDimension()!=1 || mesh1D->getSpaceDimension()!=2)
9910 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshWith1DLine works with mesh2D with spacedim=meshdim=2 and mesh1D with meshdim=1 spaceDim=2 !");
9911 // Step 1: compute all edge intersections (new nodes)
9912 std::vector< std::vector<int> > intersectEdge1, colinear2, subDiv2;
9913 std::vector<double> addCoo,addCoordsQuadratic; // coordinates of newly created nodes
9914 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
9915 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
9917 // Build desc connectivity
9918 DataArrayInt *desc1(DataArrayInt::New()),*descIndx1(DataArrayInt::New()),*revDesc1(DataArrayInt::New()),*revDescIndx1(DataArrayInt::New());
9919 MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(revDesc1),dd4(revDescIndx1);
9920 MCAuto<MEDCouplingUMesh> m1Desc(mesh2D->buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1));
9921 std::map<int,int> mergedNodes;
9922 Intersect1DMeshes(m1Desc,mesh1D,eps,intersectEdge1,colinear2,subDiv2,addCoo,mergedNodes);
9923 // use mergeNodes to fix intersectEdge1
9924 for(std::vector< std::vector<int> >::iterator it0=intersectEdge1.begin();it0!=intersectEdge1.end();it0++)
9926 std::size_t n((*it0).size()/2);
9927 int eltStart((*it0)[0]),eltEnd((*it0)[2*n-1]);
9928 std::map<int,int>::const_iterator it1;
9929 it1=mergedNodes.find(eltStart);
9930 if(it1!=mergedNodes.end())
9931 (*it0)[0]=(*it1).second;
9932 it1=mergedNodes.find(eltEnd);
9933 if(it1!=mergedNodes.end())
9934 (*it0)[2*n-1]=(*it1).second;
9937 MCAuto<DataArrayDouble> addCooDa(DataArrayDouble::New());
9938 addCooDa->useArray(&addCoo[0],false,C_DEALLOC,(int)addCoo.size()/2,2);
9939 // Step 2: re-order newly created nodes according to the ordering found in m2
9940 std::vector< std::vector<int> > intersectEdge2;
9941 BuildIntersectEdges(m1Desc,mesh1D,addCoo,subDiv2,intersectEdge2);
9943 // Step 3: compute splitMesh1D
9944 MCAuto<DataArrayInt> idsInRet1Colinear,idsInDescMesh2DForIdsInRetColinear;
9945 MCAuto<DataArrayInt> ret2(DataArrayInt::New()); ret2->alloc(0,1);
9946 MCAuto<MEDCouplingUMesh> ret1(BuildMesh1DCutFrom(mesh1D,intersectEdge2,mesh2D->getCoords(),addCoo,mergedNodes,colinear2,intersectEdge1,
9947 idsInRet1Colinear,idsInDescMesh2DForIdsInRetColinear));
9948 MCAuto<DataArrayInt> ret3(DataArrayInt::New()); ret3->alloc(ret1->getNumberOfCells()*2,1); ret3->fillWithValue(std::numeric_limits<int>::max()); ret3->rearrange(2);
9949 MCAuto<DataArrayInt> idsInRet1NotColinear(idsInRet1Colinear->buildComplement(ret1->getNumberOfCells()));
9950 // deal with cells in mesh2D that are not cut but only some of their edges are
9951 MCAuto<DataArrayInt> idsInDesc2DToBeRefined(idsInDescMesh2DForIdsInRetColinear->deepCopy());
9952 idsInDesc2DToBeRefined->abs(); idsInDesc2DToBeRefined->applyLin(1,-1);
9953 idsInDesc2DToBeRefined=idsInDesc2DToBeRefined->buildUnique();
9954 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
9955 if(!idsInDesc2DToBeRefined->empty())
9957 DataArrayInt *out0(0),*outi0(0);
9958 MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
9959 MCAuto<DataArrayInt> outi0s(outi0);
9961 out0s=out0s->buildUnique();
9965 MCAuto<MEDCouplingUMesh> ret1NonCol(static_cast<MEDCouplingUMesh *>(ret1->buildPartOfMySelf(idsInRet1NotColinear->begin(),idsInRet1NotColinear->end())));
9966 MCAuto<DataArrayDouble> baryRet1(ret1NonCol->computeCellCenterOfMass());
9967 MCAuto<DataArrayInt> elts,eltsIndex;
9968 mesh2D->getCellsContainingPoints(baryRet1->begin(),baryRet1->getNumberOfTuples(),eps,elts,eltsIndex);
9969 MCAuto<DataArrayInt> eltsIndex2(eltsIndex->deltaShiftIndex());
9970 MCAuto<DataArrayInt> eltsIndex3(eltsIndex2->findIdsEqual(1));
9971 if(eltsIndex2->count(0)+eltsIndex3->getNumberOfTuples()!=ret1NonCol->getNumberOfCells())
9972 throw INTERP_KERNEL::Exception("Intersect2DMeshWith1DLine : internal error 1 !");
9973 MCAuto<DataArrayInt> cellsToBeModified(elts->buildUnique());
9974 MCAuto<DataArrayInt> untouchedCells(cellsToBeModified->buildComplement(mesh2D->getNumberOfCells()));
9975 if((DataArrayInt *)out0s)
9976 untouchedCells=untouchedCells->buildSubstraction(out0s);//if some edges in ret1 are colinear to descending mesh of mesh2D remove cells from untouched one
9977 std::vector< MCAuto<MEDCouplingUMesh> > outMesh2DSplit;
9978 // OK all is ready to insert in ret2 mesh
9979 if(!untouchedCells->empty())
9980 {// the most easy part, cells in mesh2D not impacted at all
9981 outMesh2DSplit.push_back(static_cast<MEDCouplingUMesh *>(mesh2D->buildPartOfMySelf(untouchedCells->begin(),untouchedCells->end())));
9982 outMesh2DSplit.back()->setCoords(ret1->getCoords());
9983 ret2->pushBackValsSilent(untouchedCells->begin(),untouchedCells->end());
9985 if((DataArrayInt *)out0s)
9986 {// here dealing with cells in out0s but not in cellsToBeModified
9987 MCAuto<DataArrayInt> fewModifiedCells(out0s->buildSubstraction(cellsToBeModified));
9988 const int *rdptr(dd3->begin()),*rdiptr(dd4->begin()),*dptr(dd1->begin()),*diptr(dd2->begin());
9989 for(const int *it=fewModifiedCells->begin();it!=fewModifiedCells->end();it++)
9991 outMesh2DSplit.push_back(BuildRefined2DCell(ret1->getCoords(),mesh2D,*it,dptr+diptr[*it],dptr+diptr[*it+1],intersectEdge1));
9992 ret1->setCoords(outMesh2DSplit.back()->getCoords());
9994 int offset(ret2->getNumberOfTuples());
9995 ret2->pushBackValsSilent(fewModifiedCells->begin(),fewModifiedCells->end());
9996 MCAuto<DataArrayInt> partOfRet3(DataArrayInt::New()); partOfRet3->alloc(2*idsInRet1Colinear->getNumberOfTuples(),1);
9997 partOfRet3->fillWithValue(std::numeric_limits<int>::max()); partOfRet3->rearrange(2);
9998 int kk(0),*ret3ptr(partOfRet3->getPointer());
9999 for(const int *it=idsInDescMesh2DForIdsInRetColinear->begin();it!=idsInDescMesh2DForIdsInRetColinear->end();it++,kk++)
10001 int faceId(std::abs(*it)-1);
10002 for(const int *it2=rdptr+rdiptr[faceId];it2!=rdptr+rdiptr[faceId+1];it2++)
10004 int tmp(fewModifiedCells->findIdFirstEqual(*it2));
10007 if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],-(*it))!=dptr+diptr[*it2+1])
10008 ret3ptr[2*kk]=tmp+offset;
10009 if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],(*it))!=dptr+diptr[*it2+1])
10010 ret3ptr[2*kk+1]=tmp+offset;
10013 {//the current edge is shared by a 2D cell that will be split just after
10014 if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],-(*it))!=dptr+diptr[*it2+1])
10015 ret3ptr[2*kk]=-(*it2+1);
10016 if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],(*it))!=dptr+diptr[*it2+1])
10017 ret3ptr[2*kk+1]=-(*it2+1);
10021 m1Desc->setCoords(ret1->getCoords());
10022 ret1NonCol->setCoords(ret1->getCoords());
10023 ret3->setPartOfValues3(partOfRet3,idsInRet1Colinear->begin(),idsInRet1Colinear->end(),0,2,1,true);
10024 if(!outMesh2DSplit.empty())
10026 DataArrayDouble *da(outMesh2DSplit.back()->getCoords());
10027 for(std::vector< MCAuto<MEDCouplingUMesh> >::iterator itt=outMesh2DSplit.begin();itt!=outMesh2DSplit.end();itt++)
10028 (*itt)->setCoords(da);
10031 cellsToBeModified=cellsToBeModified->buildUniqueNotSorted();
10032 for(const int *it=cellsToBeModified->begin();it!=cellsToBeModified->end();it++)
10034 MCAuto<DataArrayInt> idsNonColPerCell(elts->findIdsEqual(*it));
10035 idsNonColPerCell->transformWithIndArr(eltsIndex3->begin(),eltsIndex3->end());
10036 MCAuto<DataArrayInt> idsNonColPerCell2(idsInRet1NotColinear->selectByTupleId(idsNonColPerCell->begin(),idsNonColPerCell->end()));
10037 MCAuto<MEDCouplingUMesh> partOfMesh1CuttingCur2DCell(static_cast<MEDCouplingUMesh *>(ret1NonCol->buildPartOfMySelf(idsNonColPerCell->begin(),idsNonColPerCell->end())));
10038 MCAuto<DataArrayInt> partOfRet3;
10039 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));
10040 ret3->setPartOfValues3(partOfRet3,idsNonColPerCell2->begin(),idsNonColPerCell2->end(),0,2,1,true);
10041 outMesh2DSplit.push_back(splitOfOneCell);
10042 for(int i=0;i<splitOfOneCell->getNumberOfCells();i++)
10043 ret2->pushBackSilent(*it);
10046 std::size_t nbOfMeshes(outMesh2DSplit.size());
10047 std::vector<const MEDCouplingUMesh *> tmp(nbOfMeshes);
10048 for(std::size_t i=0;i<nbOfMeshes;i++)
10049 tmp[i]=outMesh2DSplit[i];
10051 ret1->getCoords()->setInfoOnComponents(compNames);
10052 MCAuto<MEDCouplingUMesh> ret2D(MEDCouplingUMesh::MergeUMeshesOnSameCoords(tmp));
10053 // To finish - filter ret3 - std::numeric_limits<int>::max() -> -1 - negate values must be resolved.
10054 ret3->rearrange(1);
10055 MCAuto<DataArrayInt> edgesToDealWith(ret3->findIdsStricltyNegative());
10056 for(const int *it=edgesToDealWith->begin();it!=edgesToDealWith->end();it++)
10058 int old2DCellId(-ret3->getIJ(*it,0)-1);
10059 MCAuto<DataArrayInt> candidates(ret2->findIdsEqual(old2DCellId));
10060 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
10062 ret3->changeValue(std::numeric_limits<int>::max(),-1);
10063 ret3->rearrange(2);
10065 splitMesh1D=ret1.retn();
10066 splitMesh2D=ret2D.retn();
10067 cellIdInMesh2D=ret2.retn();
10068 cellIdInMesh1D=ret3.retn();
10072 * Private. Third step of the partitioning algorithm (Intersect2DMeshes): reconstruct full 2D cells from the
10073 * (newly created) nodes corresponding to the edge intersections.
10075 * @param[out] cr, crI connectivity of the resulting mesh
10076 * @param[out] cNb1, cNb2 correspondance arrays giving for the merged mesh the initial cells IDs in m1 / m2
10077 * TODO: describe input parameters
10079 void MEDCouplingUMesh::BuildIntersecting2DCellsFromEdges(double eps, const MEDCouplingUMesh *m1, const int *desc1, const int *descIndx1,
10080 const std::vector<std::vector<int> >& intesctEdges1, const std::vector< std::vector<int> >& colinear2,
10081 const MEDCouplingUMesh *m2, const int *desc2, const int *descIndx2, const std::vector<std::vector<int> >& intesctEdges2,
10082 const std::vector<double>& addCoords,
10083 std::vector<double>& addCoordsQuadratic, std::vector<int>& cr, std::vector<int>& crI, std::vector<int>& cNb1, std::vector<int>& cNb2)
10085 static const int SPACEDIM=2;
10086 const double *coo1(m1->getCoords()->getConstPointer());
10087 const int *conn1(m1->getNodalConnectivity()->getConstPointer()),*connI1(m1->getNodalConnectivityIndex()->getConstPointer());
10088 int offset1(m1->getNumberOfNodes());
10089 const double *coo2(m2->getCoords()->getConstPointer());
10090 const int *conn2(m2->getNodalConnectivity()->getConstPointer()),*connI2(m2->getNodalConnectivityIndex()->getConstPointer());
10091 int offset2(offset1+m2->getNumberOfNodes());
10092 int offset3(offset2+((int)addCoords.size())/2);
10093 MCAuto<DataArrayDouble> bbox1Arr(m1->getBoundingBoxForBBTree()),bbox2Arr(m2->getBoundingBoxForBBTree());
10094 const double *bbox1(bbox1Arr->begin()),*bbox2(bbox2Arr->begin());
10095 // Here a BBTree on 2D-cells, not on segments:
10096 BBTree<SPACEDIM,int> myTree(bbox2,0,0,m2->getNumberOfCells(),eps);
10097 int ncell1(m1->getNumberOfCells());
10099 for(int i=0;i<ncell1;i++)
10101 std::vector<int> candidates2;
10102 myTree.getIntersectingElems(bbox1+i*2*SPACEDIM,candidates2);
10103 std::map<INTERP_KERNEL::Node *,int> mapp;
10104 std::map<int,INTERP_KERNEL::Node *> mappRev;
10105 INTERP_KERNEL::QuadraticPolygon pol1;
10106 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn1[connI1[i]];
10107 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
10108 // Populate mapp and mappRev with nodes from the current cell (i) from mesh1 - this also builds the Node* objects:
10109 MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,/* output */mapp,mappRev);
10110 // pol1 is the full cell from mesh2, in QP format, with all the additional intersecting nodes.
10111 pol1.buildFromCrudeDataArray(mappRev,cm.isQuadratic(),conn1+connI1[i]+1,coo1,
10112 desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1);
10114 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
10115 std::set<INTERP_KERNEL::Edge *> edgesBoundary2;// store all edges that are on boundary of (pol2 intersect pol1) minus edges on pol1.
10116 INTERP_KERNEL::IteratorOnComposedEdge it1(&pol1);
10117 for(it1.first();!it1.finished();it1.next())
10118 edges1.insert(it1.current()->getPtr());
10120 std::map<int,std::vector<INTERP_KERNEL::ElementaryEdge *> > edgesIn2ForShare; // common edges
10121 std::vector<INTERP_KERNEL::QuadraticPolygon> pol2s(candidates2.size());
10123 for(std::vector<int>::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++,ii++)
10125 INTERP_KERNEL::NormalizedCellType typ2=(INTERP_KERNEL::NormalizedCellType)conn2[connI2[*it2]];
10126 const INTERP_KERNEL::CellModel& cm2=INTERP_KERNEL::CellModel::GetCellModel(typ2);
10127 // Complete mapping with elements coming from the current cell it2 in mesh2:
10128 MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,/* output */mapp,mappRev);
10129 // pol2 is the new QP in the final merged result.
10130 pol2s[ii].buildFromCrudeDataArray2(mappRev,cm2.isQuadratic(),conn2+connI2[*it2]+1,coo2,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,
10131 pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2, /* output */ edgesIn2ForShare);
10134 for(std::vector<int>::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++,ii++)
10136 INTERP_KERNEL::ComposedEdge::InitLocationsWithOther(pol1,pol2s[ii]);
10137 pol2s[ii].updateLocOfEdgeFromCrudeDataArray2(desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2);
10138 //MEDCouplingUMeshAssignOnLoc(pol1,pol2,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,colinear2);
10139 pol1.buildPartitionsAbs(pol2s[ii],edges1,edgesBoundary2,mapp,i,*it2,offset3,addCoordsQuadratic,cr,crI,cNb1,cNb2);
10141 // Deals with remaining (non-consumed) edges from m1: these are the edges that were never touched
10142 // by m2 but that we still want to keep in the final result.
10143 if(!edges1.empty())
10147 INTERP_KERNEL::QuadraticPolygon::ComputeResidual(pol1,edges1,edgesBoundary2,mapp,offset3,i,addCoordsQuadratic,cr,crI,cNb1,cNb2);
10149 catch(INTERP_KERNEL::Exception& e)
10151 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();
10152 throw INTERP_KERNEL::Exception(oss.str());
10155 for(std::map<int,INTERP_KERNEL::Node *>::const_iterator it=mappRev.begin();it!=mappRev.end();it++)
10156 (*it).second->decrRef();
10161 * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
10162 * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
10163 * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
10164 * The caller is to deal with the resulting DataArrayInt.
10165 * \throw If the coordinate array is not set.
10166 * \throw If the nodal connectivity of the cells is not defined.
10167 * \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
10168 * \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
10170 * \sa DataArrayInt::sortEachPairToMakeALinkedList
10172 DataArrayInt *MEDCouplingUMesh::orderConsecutiveCells1D() const
10174 checkFullyDefined();
10175 if(getMeshDimension()!=1)
10176 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
10178 // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
10179 MCAuto<DataArrayInt> _d(DataArrayInt::New()),_dI(DataArrayInt::New());
10180 MCAuto<DataArrayInt> _rD(DataArrayInt::New()),_rDI(DataArrayInt::New());
10181 MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
10182 const int *d(_d->getConstPointer()), *dI(_dI->getConstPointer());
10183 const int *rD(_rD->getConstPointer()), *rDI(_rDI->getConstPointer());
10184 MCAuto<DataArrayInt> _dsi(_rDI->deltaShiftIndex());
10185 const int * dsi(_dsi->getConstPointer());
10186 MCAuto<DataArrayInt> dsii = _dsi->findIdsNotInRange(0,3);
10188 if (dsii->getNumberOfTuples())
10189 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
10191 int nc(getNumberOfCells());
10192 MCAuto<DataArrayInt> result(DataArrayInt::New());
10193 result->alloc(nc,1);
10195 // set of edges not used so far
10196 std::set<int> edgeSet;
10197 for (int i=0; i<nc; edgeSet.insert(i), i++);
10201 // while we have points with only one neighbor segments
10204 std::list<int> linePiece;
10205 // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
10206 for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
10208 // Fill the list forward (resp. backward) from the start segment:
10209 int activeSeg = startSeg;
10210 int prevPointId = -20;
10212 while (!edgeSet.empty())
10214 if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
10217 linePiece.push_back(activeSeg);
10219 linePiece.push_front(activeSeg);
10220 edgeSet.erase(activeSeg);
10223 int ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
10224 ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
10225 if (dsi[ptId] == 1) // hitting the end of the line
10227 prevPointId = ptId;
10228 int seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
10229 activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
10232 // Done, save final piece into DA:
10233 std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
10234 newIdx += linePiece.size();
10236 // identify next valid start segment (one which is not consumed)
10237 if(!edgeSet.empty())
10238 startSeg = *(edgeSet.begin());
10240 while (!edgeSet.empty());
10241 return result.retn();
10246 void IKGeo2DInternalMapper2(INTERP_KERNEL::Node *n, const std::map<MCAuto<INTERP_KERNEL::Node>,int>& m, int forbVal0, int forbVal1, std::vector<int>& isect)
10248 MCAuto<INTERP_KERNEL::Node> nTmp(n); nTmp->incrRef();
10249 std::map<MCAuto<INTERP_KERNEL::Node>,int>::const_iterator it(m.find(nTmp));
10251 throw INTERP_KERNEL::Exception("Internal error in remapping !");
10252 int v((*it).second);
10253 if(v==forbVal0 || v==forbVal1)
10255 if(std::find(isect.begin(),isect.end(),v)==isect.end())
10256 isect.push_back(v);
10259 bool IKGeo2DInternalMapper(const INTERP_KERNEL::ComposedEdge& c, const std::map<MCAuto<INTERP_KERNEL::Node>,int>& m, int forbVal0, int forbVal1, std::vector<int>& isect)
10264 bool presenceOfOn(false);
10265 for(int i=0;i<sz;i++)
10267 INTERP_KERNEL::ElementaryEdge *e(c[i]);
10268 if(e->getLoc()!=INTERP_KERNEL::FULL_ON_1)
10270 IKGeo2DInternalMapper2(e->getStartNode(),m,forbVal0,forbVal1,isect);
10271 IKGeo2DInternalMapper2(e->getEndNode(),m,forbVal0,forbVal1,isect);
10273 return presenceOfOn;
10279 * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
10280 * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
10281 * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
10282 * a minimal creation of new nodes is wanted.
10283 * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
10284 * nodes if a SEG3 is split without information of middle.
10285 * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
10286 * avoid to have a non conform mesh.
10288 * \return int - the number of new nodes created (in most of cases 0).
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 * \throw If some subcells needed to be split are orphan.
10294 * \sa MEDCouplingUMesh::conformize2D
10296 int MEDCouplingUMesh::split2DCells(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *midOpt, const DataArrayInt *midOptI)
10298 if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
10299 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
10300 desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
10301 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10302 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10303 if(midOpt==0 && midOptI==0)
10305 split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
10308 else if(midOpt!=0 && midOptI!=0)
10309 return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
10311 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
10315 * \b WARNING this method is \b potentially \b non \b const (if returned array is empty).
10316 * \b WARNING this method lead to have a non geometric type sorted mesh (for MED file users) !
10317 * 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
10318 * 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).
10319 * 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.
10321 * Whatever the returned value, this method does not alter the order of cells in \a this neither the orientation of cells.
10322 * The modified cells, if any, are systematically declared as NORM_POLYGON or NORM_QPOLYG depending on the initial quadraticness of geometric type.
10324 * This method expects that \b this has a meshDim equal 2 and spaceDim equal to 2 too.
10325 * This method expects that all nodes in \a this are not closer than \a eps.
10326 * If it is not the case you can invoke MEDCouplingUMesh::mergeNodes before calling this method.
10328 * \param [in] eps the relative error to detect merged edges.
10329 * \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
10330 * that the user is expected to deal with.
10332 * \throw If \a this is not coherent.
10333 * \throw If \a this has not spaceDim equal to 2.
10334 * \throw If \a this has not meshDim equal to 2.
10335 * \sa MEDCouplingUMesh::mergeNodes, MEDCouplingUMesh::split2DCells
10337 DataArrayInt *MEDCouplingUMesh::conformize2D(double eps)
10339 static const int SPACEDIM=2;
10340 checkConsistencyLight();
10341 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10342 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::conformize2D : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10343 MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
10344 MCAuto<MEDCouplingUMesh> mDesc(buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));
10345 const int *c(mDesc->getNodalConnectivity()->getConstPointer()),*ci(mDesc->getNodalConnectivityIndex()->getConstPointer()),*rd(revDesc1->getConstPointer()),*rdi(revDescIndx1->getConstPointer());
10346 MCAuto<DataArrayDouble> bboxArr(mDesc->getBoundingBoxForBBTree());
10347 const double *bbox(bboxArr->begin()),*coords(getCoords()->begin());
10348 int nCell(getNumberOfCells()),nDescCell(mDesc->getNumberOfCells());
10349 std::vector< std::vector<int> > intersectEdge(nDescCell),overlapEdge(nDescCell);
10350 std::vector<double> addCoo;
10351 BBTree<SPACEDIM,int> myTree(bbox,0,0,nDescCell,-eps);
10352 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10353 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10354 for(int i=0;i<nDescCell;i++)
10356 std::vector<int> candidates;
10357 myTree.getIntersectingElems(bbox+i*2*SPACEDIM,candidates);
10358 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
10361 std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
10362 INTERP_KERNEL::Edge *e1(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coords,m)),
10363 *e2(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[*it]],c+ci[*it]+1,coords,m));
10364 INTERP_KERNEL::MergePoints merge;
10365 INTERP_KERNEL::QuadraticPolygon c1,c2;
10366 e1->intersectWith(e2,merge,c1,c2);
10367 e1->decrRef(); e2->decrRef();
10368 if(IKGeo2DInternalMapper(c1,m,c[ci[i]+1],c[ci[i]+2],intersectEdge[i]))
10369 overlapEdge[i].push_back(*it);
10370 if(IKGeo2DInternalMapper(c2,m,c[ci[*it]+1],c[ci[*it]+2],intersectEdge[*it]))
10371 overlapEdge[*it].push_back(i);
10374 // splitting done. sort intersect point in intersectEdge.
10375 std::vector< std::vector<int> > middle(nDescCell);
10376 int nbOf2DCellsToBeSplit(0);
10377 bool middleNeedsToBeUsed(false);
10378 std::vector<bool> cells2DToTreat(nDescCell,false);
10379 for(int i=0;i<nDescCell;i++)
10381 std::vector<int>& isect(intersectEdge[i]);
10382 int sz((int)isect.size());
10385 std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
10386 INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coords,m));
10387 e->sortSubNodesAbs(coords,isect);
10392 int idx0(rdi[i]),idx1(rdi[i+1]);
10394 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::conformize2D : internal error #0 !");
10395 if(!cells2DToTreat[rd[idx0]])
10397 cells2DToTreat[rd[idx0]]=true;
10398 nbOf2DCellsToBeSplit++;
10400 // try to reuse at most eventual 'middle' of SEG3
10401 std::vector<int>& mid(middle[i]);
10402 mid.resize(sz+1,-1);
10403 if((INTERP_KERNEL::NormalizedCellType)c[ci[i]]==INTERP_KERNEL::NORM_SEG3)
10405 middleNeedsToBeUsed=true;
10406 const std::vector<int>& candidates(overlapEdge[i]);
10407 std::vector<int> trueCandidates;
10408 for(std::vector<int>::const_iterator itc=candidates.begin();itc!=candidates.end();itc++)
10409 if((INTERP_KERNEL::NormalizedCellType)c[ci[*itc]]==INTERP_KERNEL::NORM_SEG3)
10410 trueCandidates.push_back(*itc);
10411 int stNode(c[ci[i]+1]),endNode(isect[0]);
10412 for(int j=0;j<sz+1;j++)
10414 for(std::vector<int>::const_iterator itc=trueCandidates.begin();itc!=trueCandidates.end();itc++)
10416 int tmpSt(c[ci[*itc]+1]),tmpEnd(c[ci[*itc]+2]);
10417 if((tmpSt==stNode && tmpEnd==endNode) || (tmpSt==endNode && tmpEnd==stNode))
10418 { mid[j]=*itc; break; }
10421 endNode=j<sz-1?isect[j+1]:c[ci[i]+2];
10426 MCAuto<DataArrayInt> ret(DataArrayInt::New()),notRet(DataArrayInt::New()); ret->alloc(nbOf2DCellsToBeSplit,1);
10427 if(nbOf2DCellsToBeSplit==0)
10430 int *retPtr(ret->getPointer());
10431 for(int i=0;i<nCell;i++)
10432 if(cells2DToTreat[i])
10435 MCAuto<DataArrayInt> mSafe,nSafe,oSafe,pSafe,qSafe,rSafe;
10436 DataArrayInt *m(0),*n(0),*o(0),*p(0),*q(0),*r(0);
10437 MEDCouplingUMesh::ExtractFromIndexedArrays(ret->begin(),ret->end(),desc1,descIndx1,m,n); mSafe=m; nSafe=n;
10438 DataArrayInt::PutIntoToSkylineFrmt(intersectEdge,o,p); oSafe=o; pSafe=p;
10439 if(middleNeedsToBeUsed)
10440 { DataArrayInt::PutIntoToSkylineFrmt(middle,q,r); qSafe=q; rSafe=r; }
10441 MCAuto<MEDCouplingUMesh> modif(static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(ret->begin(),ret->end(),true)));
10442 int nbOfNodesCreated(modif->split2DCells(mSafe,nSafe,oSafe,pSafe,qSafe,rSafe));
10443 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.
10444 setPartOfMySelf(ret->begin(),ret->end(),*modif);
10446 bool areNodesMerged; int newNbOfNodes;
10447 if(nbOfNodesCreated!=0)
10448 MCAuto<DataArrayInt> tmp(mergeNodes(eps,areNodesMerged,newNbOfNodes));
10454 * 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.
10455 * 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).
10456 * 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
10457 * to invoke MEDCouplingUMesh::mergeNodes and MEDCouplingUMesh::conformize2D right after this call.
10458 * 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
10459 * new nodes for center of merged edges is are systematically created and appended at the end of the previously existing nodes.
10461 * 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
10462 * using new instance, idem for coordinates.
10464 * 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.
10466 * \return DataArrayInt * - The list of cellIds in \a this that have at least one edge colinearized.
10468 * \throw If \a this is not coherent.
10469 * \throw If \a this has not spaceDim equal to 2.
10470 * \throw If \a this has not meshDim equal to 2.
10472 * \sa MEDCouplingUMesh::conformize2D, MEDCouplingUMesh::mergeNodes, MEDCouplingUMesh::convexEnvelop2D.
10474 DataArrayInt *MEDCouplingUMesh::colinearize2D(double eps)
10476 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
10477 checkConsistencyLight();
10478 if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10479 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::colinearize2D : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10480 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10481 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10482 int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
10483 const int *cptr(_nodal_connec->begin()),*ciptr(_nodal_connec_index->begin());
10484 MCAuto<DataArrayInt> newc(DataArrayInt::New()),newci(DataArrayInt::New()); newci->alloc(nbOfCells+1,1); newc->alloc(0,1); newci->setIJ(0,0,0);
10485 MCAuto<DataArrayDouble> appendedCoords(DataArrayDouble::New()); appendedCoords->alloc(0,1);//1 not 2 it is not a bug.
10486 const double *coords(_coords->begin());
10487 int *newciptr(newci->getPointer());
10488 for(int i=0;i<nbOfCells;i++,newciptr++,ciptr++)
10490 if(Colinearize2DCell(coords,cptr+ciptr[0],cptr+ciptr[1],nbOfNodes,newc,appendedCoords))
10491 ret->pushBackSilent(i);
10492 newciptr[1]=newc->getNumberOfTuples();
10497 if(!appendedCoords->empty())
10499 appendedCoords->rearrange(2);
10500 MCAuto<DataArrayDouble> newCoords(DataArrayDouble::Aggregate(getCoords(),appendedCoords));//treat info on components
10502 setCoords(newCoords);
10505 setConnectivity(newc,newci,true);
10510 * \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.
10511 * 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.
10512 * And for each j in [1,n) intersect[i][2*(j-1)+1]==intersect[i][2*j].
10513 * \param [out] subDiv2 - for each cell in \a m2Desc returns nodes that split it using convention \a m1Desc first, then \a m2Desc, then addCoo
10514 * \param [out] colinear2 - for each cell in \a m2Desc returns the edges in \a m1Desc that are colinear to it.
10515 * \param [out] addCoo - nodes to be append at the end
10516 * \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.
10518 void MEDCouplingUMesh::Intersect1DMeshes(const MEDCouplingUMesh *m1Desc, const MEDCouplingUMesh *m2Desc, double eps,
10519 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)
10521 static const int SPACEDIM=2;
10522 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10523 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10524 const int *c1(m1Desc->getNodalConnectivity()->getConstPointer()),*ci1(m1Desc->getNodalConnectivityIndex()->getConstPointer());
10525 // Build BB tree of all edges in the tool mesh (second mesh)
10526 MCAuto<DataArrayDouble> bbox1Arr(m1Desc->getBoundingBoxForBBTree()),bbox2Arr(m2Desc->getBoundingBoxForBBTree());
10527 const double *bbox1(bbox1Arr->begin()),*bbox2(bbox2Arr->begin());
10528 int nDescCell1(m1Desc->getNumberOfCells()),nDescCell2(m2Desc->getNumberOfCells());
10529 intersectEdge1.resize(nDescCell1);
10530 colinear2.resize(nDescCell2);
10531 subDiv2.resize(nDescCell2);
10532 BBTree<SPACEDIM,int> myTree(bbox2,0,0,m2Desc->getNumberOfCells(),-eps);
10534 std::vector<int> candidates1(1);
10535 int offset1(m1Desc->getNumberOfNodes());
10536 int offset2(offset1+m2Desc->getNumberOfNodes());
10537 for(int i=0;i<nDescCell1;i++) // for all edges in the first mesh
10539 std::vector<int> candidates2; // edges of mesh2 candidate for intersection
10540 myTree.getIntersectingElems(bbox1+i*2*SPACEDIM,candidates2);
10541 if(!candidates2.empty()) // candidates2 holds edges from the second mesh potentially intersecting current edge i in mesh1
10543 std::map<INTERP_KERNEL::Node *,int> map1,map2;
10544 // pol2 is not necessarily a closed polygon: just a set of (quadratic) edges (same as candidates2) in the Geometric DS format
10545 INTERP_KERNEL::QuadraticPolygon *pol2=MEDCouplingUMeshBuildQPFromMesh(m2Desc,candidates2,map2);
10547 INTERP_KERNEL::QuadraticPolygon *pol1=MEDCouplingUMeshBuildQPFromMesh(m1Desc,candidates1,map1);
10548 // 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
10549 // This trick guarantees that Node * are discriminant (i.e. form a unique identifier)
10550 std::set<INTERP_KERNEL::Node *> nodes;
10551 pol1->getAllNodes(nodes); pol2->getAllNodes(nodes);
10552 std::size_t szz(nodes.size());
10553 std::vector< MCAuto<INTERP_KERNEL::Node> > nodesSafe(szz);
10554 std::set<INTERP_KERNEL::Node *>::const_iterator itt(nodes.begin());
10555 for(std::size_t iii=0;iii<szz;iii++,itt++)
10556 { (*itt)->incrRef(); nodesSafe[iii]=*itt; }
10557 // end of protection
10558 // Performs egde cutting:
10559 pol1->splitAbs(*pol2,map1,map2,offset1,offset2,candidates2,intersectEdge1[i],i,colinear2,subDiv2,addCoo,mergedNodes);
10564 // Copy the edge (take only the two first points, ie discard quadratic point at this stage)
10565 intersectEdge1[i].insert(intersectEdge1[i].end(),c1+ci1[i]+1,c1+ci1[i]+3);
10570 * This method is private and is the first step of Partition of 2D mesh (spaceDim==2 and meshDim==2).
10571 * It builds the descending connectivity of the two meshes, and then using a binary tree
10572 * it computes the edge intersections. This results in new points being created : they're stored in addCoo.
10573 * Documentation about parameters colinear2 and subDiv2 can be found in method QuadraticPolygon::splitAbs().
10575 void MEDCouplingUMesh::IntersectDescending2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2, double eps,
10576 std::vector< std::vector<int> >& intersectEdge1, std::vector< std::vector<int> >& colinear2, std::vector< std::vector<int> >& subDiv2,
10577 MEDCouplingUMesh *& m1Desc, DataArrayInt *&desc1, DataArrayInt *&descIndx1, DataArrayInt *&revDesc1, DataArrayInt *&revDescIndx1,
10578 std::vector<double>& addCoo,
10579 MEDCouplingUMesh *& m2Desc, DataArrayInt *&desc2, DataArrayInt *&descIndx2, DataArrayInt *&revDesc2, DataArrayInt *&revDescIndx2)
10581 // Build desc connectivity
10582 desc1=DataArrayInt::New(); descIndx1=DataArrayInt::New(); revDesc1=DataArrayInt::New(); revDescIndx1=DataArrayInt::New();
10583 desc2=DataArrayInt::New();
10584 descIndx2=DataArrayInt::New();
10585 revDesc2=DataArrayInt::New();
10586 revDescIndx2=DataArrayInt::New();
10587 MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(revDesc1),dd4(revDescIndx1);
10588 MCAuto<DataArrayInt> dd5(desc2),dd6(descIndx2),dd7(revDesc2),dd8(revDescIndx2);
10589 m1Desc=m1->buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1);
10590 m2Desc=m2->buildDescendingConnectivity2(desc2,descIndx2,revDesc2,revDescIndx2);
10591 MCAuto<MEDCouplingUMesh> dd9(m1Desc),dd10(m2Desc);
10592 std::map<int,int> notUsedMap;
10593 Intersect1DMeshes(m1Desc,m2Desc,eps,intersectEdge1,colinear2,subDiv2,addCoo,notUsedMap);
10594 m1Desc->incrRef(); desc1->incrRef(); descIndx1->incrRef(); revDesc1->incrRef(); revDescIndx1->incrRef();
10595 m2Desc->incrRef(); desc2->incrRef(); descIndx2->incrRef(); revDesc2->incrRef(); revDescIndx2->incrRef();
10599 * This method performs the 2nd step of Partition of 2D mesh.
10600 * This method has 4 inputs :
10601 * - a mesh 'm1' with meshDim==1 and a SpaceDim==2
10602 * - a mesh 'm2' with meshDim==1 and a SpaceDim==2
10603 * - subDiv of size 'm2->getNumberOfCells()' that lists for each seg cell in 'm' the splitting node ids randomly sorted.
10604 * 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'
10605 * Nodes end up lying consecutively on a cutted edge.
10606 * \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.
10607 * (Only present for its coords in case of 'subDiv' shares some nodes of 'm1')
10608 * \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.
10609 * \param addCoo input parameter with additional nodes linked to intersection of the 2 meshes.
10610 * \param[out] intersectEdge the same content as subDiv, but correclty oriented.
10612 void MEDCouplingUMesh::BuildIntersectEdges(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2,
10613 const std::vector<double>& addCoo,
10614 const std::vector< std::vector<int> >& subDiv, std::vector< std::vector<int> >& intersectEdge)
10616 int offset1=m1->getNumberOfNodes();
10617 int ncell=m2->getNumberOfCells();
10618 const int *c=m2->getNodalConnectivity()->getConstPointer();
10619 const int *cI=m2->getNodalConnectivityIndex()->getConstPointer();
10620 const double *coo=m2->getCoords()->getConstPointer();
10621 const double *cooBis=m1->getCoords()->getConstPointer();
10622 int offset2=offset1+m2->getNumberOfNodes();
10623 intersectEdge.resize(ncell);
10624 for(int i=0;i<ncell;i++,cI++)
10626 const std::vector<int>& divs=subDiv[i];
10627 int nnode=cI[1]-cI[0]-1;
10628 std::map<int, std::pair<INTERP_KERNEL::Node *,bool> > mapp2;
10629 std::map<INTERP_KERNEL::Node *, int> mapp22;
10630 for(int j=0;j<nnode;j++)
10632 INTERP_KERNEL::Node *nn=new INTERP_KERNEL::Node(coo[2*c[(*cI)+j+1]],coo[2*c[(*cI)+j+1]+1]);
10633 int nnid=c[(*cI)+j+1];
10634 mapp2[nnid]=std::pair<INTERP_KERNEL::Node *,bool>(nn,true);
10635 mapp22[nn]=nnid+offset1;
10637 INTERP_KERNEL::Edge *e=MEDCouplingUMeshBuildQPFromEdge((INTERP_KERNEL::NormalizedCellType)c[*cI],mapp2,c+(*cI)+1);
10638 for(std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >::const_iterator it=mapp2.begin();it!=mapp2.end();it++)
10639 ((*it).second.first)->decrRef();
10640 std::vector<INTERP_KERNEL::Node *> addNodes(divs.size());
10641 std::map<INTERP_KERNEL::Node *,int> mapp3;
10642 for(std::size_t j=0;j<divs.size();j++)
10645 INTERP_KERNEL::Node *tmp=0;
10647 tmp=new INTERP_KERNEL::Node(cooBis[2*id],cooBis[2*id+1]);
10648 else if(id<offset2)
10649 tmp=new INTERP_KERNEL::Node(coo[2*(id-offset1)],coo[2*(id-offset1)+1]);//if it happens, bad news mesh 'm2' is non conform.
10651 tmp=new INTERP_KERNEL::Node(addCoo[2*(id-offset2)],addCoo[2*(id-offset2)+1]);
10655 e->sortIdsAbs(addNodes,mapp22,mapp3,intersectEdge[i]);
10656 for(std::vector<INTERP_KERNEL::Node *>::const_iterator it=addNodes.begin();it!=addNodes.end();it++)
10663 * 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).
10664 * 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
10665 * with a plane. The result will be put in 'cut3DSuf' out parameter.
10666 * \param [in] cut3DCurve input paramter that gives for each 3DCurve cell if it owns fully to the plane or partially.
10667 * \param [out] nodesOnPlane, returns all the nodes that are on the plane.
10668 * \param [in] nodal3DSurf is the nodal connectivity of 3D surf mesh.
10669 * \param [in] nodalIndx3DSurf is the nodal connectivity index of 3D surf mesh.
10670 * \param [in] nodal3DCurve is the nodal connectivity of 3D curve mesh.
10671 * \param [in] nodal3DIndxCurve is the nodal connectivity index of 3D curve mesh.
10672 * \param [in] desc is the descending connectivity 3DSurf->3DCurve
10673 * \param [in] descIndx is the descending connectivity index 3DSurf->3DCurve
10674 * \param [out] cut3DSuf input/output param.
10676 void MEDCouplingUMesh::AssemblyForSplitFrom3DCurve(const std::vector<int>& cut3DCurve, std::vector<int>& nodesOnPlane, const int *nodal3DSurf, const int *nodalIndx3DSurf,
10677 const int *nodal3DCurve, const int *nodalIndx3DCurve,
10678 const int *desc, const int *descIndx,
10679 std::vector< std::pair<int,int> >& cut3DSurf)
10681 std::set<int> nodesOnP(nodesOnPlane.begin(),nodesOnPlane.end());
10682 int nbOf3DSurfCell=(int)cut3DSurf.size();
10683 for(int i=0;i<nbOf3DSurfCell;i++)
10685 std::vector<int> res;
10686 int offset=descIndx[i];
10687 int nbOfSeg=descIndx[i+1]-offset;
10688 for(int j=0;j<nbOfSeg;j++)
10690 int edgeId=desc[offset+j];
10691 int status=cut3DCurve[edgeId];
10695 res.push_back(status);
10698 res.push_back(nodal3DCurve[nodalIndx3DCurve[edgeId]+1]);
10699 res.push_back(nodal3DCurve[nodalIndx3DCurve[edgeId]+2]);
10707 cut3DSurf[i].first=res[0]; cut3DSurf[i].second=res[1];
10713 std::set<int> s1(nodal3DSurf+nodalIndx3DSurf[i]+1,nodal3DSurf+nodalIndx3DSurf[i+1]);
10714 std::set_intersection(nodesOnP.begin(),nodesOnP.end(),s1.begin(),s1.end(),std::back_insert_iterator< std::vector<int> >(res));
10717 cut3DSurf[i].first=res[0]; cut3DSurf[i].second=res[1];
10721 cut3DSurf[i].first=-1; cut3DSurf[i].second=-1;
10726 {// case when plane is on a multi colinear edge of a polyhedron
10727 if((int)res.size()==2*nbOfSeg)
10729 cut3DSurf[i].first=-2; cut3DSurf[i].second=i;
10732 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AssemblyPointsFrom3DCurve : unexpected situation !");
10739 * \a this is expected to be a mesh with spaceDim==3 and meshDim==3. If not an exception will be thrown.
10740 * 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).
10741 * 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
10742 * with a plane. The result will be put in 'nodalRes' 'nodalResIndx' and 'cellIds' out parameters.
10743 * \param cut3DSurf input paramter that gives for each 3DSurf its intersection with plane (result of MEDCouplingUMesh::AssemblyForSplitFrom3DCurve).
10744 * \param desc is the descending connectivity 3D->3DSurf
10745 * \param descIndx is the descending connectivity index 3D->3DSurf
10747 void MEDCouplingUMesh::assemblyForSplitFrom3DSurf(const std::vector< std::pair<int,int> >& cut3DSurf,
10748 const int *desc, const int *descIndx,
10749 DataArrayInt *nodalRes, DataArrayInt *nodalResIndx, DataArrayInt *cellIds) const
10751 checkFullyDefined();
10752 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
10753 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::assemblyForSplitFrom3DSurf works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
10754 const int *nodal3D=_nodal_connec->getConstPointer();
10755 const int *nodalIndx3D=_nodal_connec_index->getConstPointer();
10756 int nbOfCells=getNumberOfCells();
10757 for(int i=0;i<nbOfCells;i++)
10759 std::map<int, std::set<int> > m;
10760 int offset=descIndx[i];
10761 int nbOfFaces=descIndx[i+1]-offset;
10764 for(int j=0;j<nbOfFaces;j++)
10766 const std::pair<int,int>& p=cut3DSurf[desc[offset+j]];
10767 if(p.first!=-1 && p.second!=-1)
10771 start=p.first; end=p.second;
10772 m[p.first].insert(p.second);
10773 m[p.second].insert(p.first);
10777 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodal3D[nodalIndx3D[i]]);
10778 int sz=nodalIndx3D[i+1]-nodalIndx3D[i]-1;
10779 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
10780 INTERP_KERNEL::NormalizedCellType cmsId;
10781 unsigned nbOfNodesSon=cm.fillSonCellNodalConnectivity2(j,nodal3D+nodalIndx3D[i]+1,sz,tmp,cmsId);
10782 start=tmp[0]; end=tmp[nbOfNodesSon-1];
10783 for(unsigned k=0;k<nbOfNodesSon;k++)
10785 m[tmp[k]].insert(tmp[(k+1)%nbOfNodesSon]);
10786 m[tmp[(k+1)%nbOfNodesSon]].insert(tmp[k]);
10793 std::vector<int> conn(1,(int)INTERP_KERNEL::NORM_POLYGON);
10797 std::map<int, std::set<int> >::const_iterator it=m.find(start);
10798 const std::set<int>& s=(*it).second;
10799 std::set<int> s2; s2.insert(prev);
10801 std::set_difference(s.begin(),s.end(),s2.begin(),s2.end(),inserter(s3,s3.begin()));
10804 int val=*s3.begin();
10805 conn.push_back(start);
10812 conn.push_back(end);
10815 nodalRes->insertAtTheEnd(conn.begin(),conn.end());
10816 nodalResIndx->pushBackSilent(nodalRes->getNumberOfTuples());
10817 cellIds->pushBackSilent(i);
10823 * 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
10824 * 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
10825 * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
10826 * 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
10827 * 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.
10829 * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
10831 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const int *nodalConnBg, const int *nodalConnEnd, DataArrayInt *nodalConnecOut)
10833 std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
10836 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
10837 if(cm.getDimension()==2)
10839 const int *node=nodalConnBg+1;
10840 int startNode=*node++;
10841 double refX=coords[2*startNode];
10842 for(;node!=nodalConnEnd;node++)
10844 if(coords[2*(*node)]<refX)
10847 refX=coords[2*startNode];
10850 std::vector<int> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
10854 double angle0=-M_PI/2;
10859 double angleNext=0.;
10860 while(nextNode!=startNode)
10864 for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
10866 if(*node!=tmpOut.back() && *node!=prevNode)
10868 tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
10869 double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
10874 res=angle0-angleM+2.*M_PI;
10883 if(nextNode!=startNode)
10885 angle0=angleNext-M_PI;
10888 prevNode=tmpOut.back();
10889 tmpOut.push_back(nextNode);
10892 std::vector<int> tmp3(2*(sz-1));
10893 std::vector<int>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
10894 std::copy(nodalConnBg+1,nodalConnEnd,it);
10895 if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
10897 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
10900 if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
10902 nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
10907 nodalConnecOut->pushBackSilent((int)INTERP_KERNEL::NORM_POLYGON);
10908 nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
10913 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
10916 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
10920 * This method works on an input pair (\b arr, \b arrIndx) where \b arr indexes is in \b arrIndx.
10921 * 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.
10923 * \param [in] idsToRemoveBg begin of set of ids to remove in \b arr (included)
10924 * \param [in] idsToRemoveEnd end of set of ids to remove in \b arr (excluded)
10925 * \param [in,out] arr array in which the remove operation will be done.
10926 * \param [in,out] arrIndx array in the remove operation will modify
10927 * \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])
10928 * \return true if \b arr and \b arrIndx have been modified, false if not.
10930 bool MEDCouplingUMesh::RemoveIdsFromIndexedArrays(const int *idsToRemoveBg, const int *idsToRemoveEnd, DataArrayInt *arr, DataArrayInt *arrIndx, int offsetForRemoval)
10932 if(!arrIndx || !arr)
10933 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : some input arrays are empty !");
10934 if(offsetForRemoval<0)
10935 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : offsetForRemoval should be >=0 !");
10936 std::set<int> s(idsToRemoveBg,idsToRemoveEnd);
10937 int nbOfGrps=arrIndx->getNumberOfTuples()-1;
10938 int *arrIPtr=arrIndx->getPointer();
10940 int previousArrI=0;
10941 const int *arrPtr=arr->getConstPointer();
10942 std::vector<int> arrOut;//no utility to switch to DataArrayInt because copy always needed
10943 for(int i=0;i<nbOfGrps;i++,arrIPtr++)
10945 if(*arrIPtr-previousArrI>offsetForRemoval)
10947 for(const int *work=arrPtr+previousArrI+offsetForRemoval;work!=arrPtr+*arrIPtr;work++)
10949 if(s.find(*work)==s.end())
10950 arrOut.push_back(*work);
10953 previousArrI=*arrIPtr;
10954 *arrIPtr=(int)arrOut.size();
10956 if(arr->getNumberOfTuples()==(int)arrOut.size())
10958 arr->alloc((int)arrOut.size(),1);
10959 std::copy(arrOut.begin(),arrOut.end(),arr->getPointer());
10964 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
10965 * (\ref numbering-indirect).
10966 * This method returns the result of the extraction ( specified by a set of ids in [\b idsOfSelectBg , \b idsOfSelectEnd ) ).
10967 * The selection of extraction is done standardly in new2old format.
10968 * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
10970 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
10971 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
10972 * \param [in] arrIn arr origin array from which the extraction will be done.
10973 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
10974 * \param [out] arrOut the resulting array
10975 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
10976 * \sa MEDCouplingUMesh::ExtractFromIndexedArraysSlice
10978 void MEDCouplingUMesh::ExtractFromIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
10979 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
10981 if(!arrIn || !arrIndxIn)
10982 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input pointer is NULL !");
10983 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
10984 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
10985 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input arrays must have exactly one component !");
10986 std::size_t sz=std::distance(idsOfSelectBg,idsOfSelectEnd);
10987 const int *arrInPtr=arrIn->getConstPointer();
10988 const int *arrIndxPtr=arrIndxIn->getConstPointer();
10989 int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
10991 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
10992 int maxSizeOfArr=arrIn->getNumberOfTuples();
10993 MCAuto<DataArrayInt> arro=DataArrayInt::New();
10994 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
10995 arrIo->alloc((int)(sz+1),1);
10996 const int *idsIt=idsOfSelectBg;
10997 int *work=arrIo->getPointer();
11000 for(std::size_t i=0;i<sz;i++,work++,idsIt++)
11002 if(*idsIt>=0 && *idsIt<nbOfGrps)
11003 lgth+=arrIndxPtr[*idsIt+1]-arrIndxPtr[*idsIt];
11006 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " ! Must be in [0," << nbOfGrps << ") !";
11007 throw INTERP_KERNEL::Exception(oss.str());
11013 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " and at this pos arrIndxIn[" << *idsIt;
11014 oss << "+1]-arrIndxIn[" << *idsIt << "] < 0 ! The input index array is bugged !";
11015 throw INTERP_KERNEL::Exception(oss.str());
11018 arro->alloc(lgth,1);
11019 work=arro->getPointer();
11020 idsIt=idsOfSelectBg;
11021 for(std::size_t i=0;i<sz;i++,idsIt++)
11023 if(arrIndxPtr[*idsIt]>=0 && arrIndxPtr[*idsIt+1]<=maxSizeOfArr)
11024 work=std::copy(arrInPtr+arrIndxPtr[*idsIt],arrInPtr+arrIndxPtr[*idsIt+1],work);
11027 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " arrIndx[" << *idsIt << "] must be >= 0 and arrIndx[";
11028 oss << *idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
11029 throw INTERP_KERNEL::Exception(oss.str());
11032 arrOut=arro.retn();
11033 arrIndexOut=arrIo.retn();
11037 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
11038 * (\ref numbering-indirect).
11039 * 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 ).
11040 * The selection of extraction is done standardly in new2old format.
11041 * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
11043 * \param [in] idsOfSelectStart begin of set of ids of the input extraction (included)
11044 * \param [in] idsOfSelectStop end of set of ids of the input extraction (excluded)
11045 * \param [in] idsOfSelectStep
11046 * \param [in] arrIn arr origin array from which the extraction will be done.
11047 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11048 * \param [out] arrOut the resulting array
11049 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11050 * \sa MEDCouplingUMesh::ExtractFromIndexedArrays
11052 void MEDCouplingUMesh::ExtractFromIndexedArraysSlice(int idsOfSelectStart, int idsOfSelectStop, int idsOfSelectStep, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11053 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11055 if(!arrIn || !arrIndxIn)
11056 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input pointer is NULL !");
11057 arrIn->checkAllocated(); arrIndxIn->checkAllocated();
11058 if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
11059 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input arrays must have exactly one component !");
11060 int sz=DataArrayInt::GetNumberOfItemGivenBESRelative(idsOfSelectStart,idsOfSelectStop,idsOfSelectStep,"MEDCouplingUMesh::ExtractFromIndexedArraysSlice : Input slice ");
11061 const int *arrInPtr=arrIn->getConstPointer();
11062 const int *arrIndxPtr=arrIndxIn->getConstPointer();
11063 int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
11065 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
11066 int maxSizeOfArr=arrIn->getNumberOfTuples();
11067 MCAuto<DataArrayInt> arro=DataArrayInt::New();
11068 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11069 arrIo->alloc((int)(sz+1),1);
11070 int idsIt=idsOfSelectStart;
11071 int *work=arrIo->getPointer();
11074 for(int i=0;i<sz;i++,work++,idsIt+=idsOfSelectStep)
11076 if(idsIt>=0 && idsIt<nbOfGrps)
11077 lgth+=arrIndxPtr[idsIt+1]-arrIndxPtr[idsIt];
11080 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " ! Must be in [0," << nbOfGrps << ") !";
11081 throw INTERP_KERNEL::Exception(oss.str());
11087 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " and at this pos arrIndxIn[" << idsIt;
11088 oss << "+1]-arrIndxIn[" << idsIt << "] < 0 ! The input index array is bugged !";
11089 throw INTERP_KERNEL::Exception(oss.str());
11092 arro->alloc(lgth,1);
11093 work=arro->getPointer();
11094 idsIt=idsOfSelectStart;
11095 for(int i=0;i<sz;i++,idsIt+=idsOfSelectStep)
11097 if(arrIndxPtr[idsIt]>=0 && arrIndxPtr[idsIt+1]<=maxSizeOfArr)
11098 work=std::copy(arrInPtr+arrIndxPtr[idsIt],arrInPtr+arrIndxPtr[idsIt+1],work);
11101 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " arrIndx[" << idsIt << "] must be >= 0 and arrIndx[";
11102 oss << idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
11103 throw INTERP_KERNEL::Exception(oss.str());
11106 arrOut=arro.retn();
11107 arrIndexOut=arrIo.retn();
11111 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11112 * 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
11113 * cellIds \b in [ \b idsOfSelectBg , \b idsOfSelectEnd ) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
11114 * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
11116 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
11117 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
11118 * \param [in] arrIn arr origin array from which the extraction will be done.
11119 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11120 * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg, \b idsOfSelectEnd )
11121 * \param [in] srcArrIndex index array of \b srcArr
11122 * \param [out] arrOut the resulting array
11123 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11125 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
11127 void MEDCouplingUMesh::SetPartOfIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11128 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
11129 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11131 if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11132 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArrays : presence of null pointer in input parameter !");
11133 MCAuto<DataArrayInt> arro=DataArrayInt::New();
11134 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11135 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11136 std::vector<bool> v(nbOfTuples,true);
11138 const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11139 const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11140 for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
11142 if(*it>=0 && *it<nbOfTuples)
11145 offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[*it+1]-arrIndxInPtr[*it]);
11149 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArrays : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
11150 throw INTERP_KERNEL::Exception(oss.str());
11153 srcArrIndexPtr=srcArrIndex->getConstPointer();
11154 arrIo->alloc(nbOfTuples+1,1);
11155 arro->alloc(arrIn->getNumberOfTuples()+offset,1);
11156 const int *arrInPtr=arrIn->getConstPointer();
11157 const int *srcArrPtr=srcArr->getConstPointer();
11158 int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
11159 int *arroPtr=arro->getPointer();
11160 for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
11164 arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
11165 *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
11169 std::size_t pos=std::distance(idsOfSelectBg,std::find(idsOfSelectBg,idsOfSelectEnd,ii));
11170 arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
11171 *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
11174 arrOut=arro.retn();
11175 arrIndexOut=arrIo.retn();
11179 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11180 * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
11182 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
11183 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
11184 * \param [in,out] arrInOut arr origin array from which the extraction will be done.
11185 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11186 * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg , \b idsOfSelectEnd )
11187 * \param [in] srcArrIndex index array of \b srcArr
11189 * \sa MEDCouplingUMesh::SetPartOfIndexedArrays
11191 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(const int *idsOfSelectBg, const int *idsOfSelectEnd, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
11192 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
11194 if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11195 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : presence of null pointer in input parameter !");
11196 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11197 const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11198 const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11199 int *arrInOutPtr=arrInOut->getPointer();
11200 const int *srcArrPtr=srcArr->getConstPointer();
11201 for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
11203 if(*it>=0 && *it<nbOfTuples)
11205 if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[*it+1]-arrIndxInPtr[*it])
11206 std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[*it]);
11209 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] !";
11210 throw INTERP_KERNEL::Exception(oss.str());
11215 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
11216 throw INTERP_KERNEL::Exception(oss.str());
11222 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
11223 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
11224 * 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]].
11225 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
11226 * A negative value in \b arrIn means that it is ignored.
11227 * 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.
11229 * \param [in] arrIn arr origin array from which the extraction will be done.
11230 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11231 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
11232 * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
11234 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn)
11236 int seed=0,nbOfDepthPeelingPerformed=0;
11237 return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
11241 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
11242 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
11243 * 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]].
11244 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
11245 * A negative value in \b arrIn means that it is ignored.
11246 * 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.
11247 * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
11248 * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
11249 * \param [in] arrIn arr origin array from which the extraction will be done.
11250 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11251 * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
11252 * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
11253 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
11254 * \sa MEDCouplingUMesh::partitionBySpreadZone
11256 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed)
11258 nbOfDepthPeelingPerformed=0;
11260 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
11261 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11264 DataArrayInt *ret=DataArrayInt::New(); ret->alloc(0,1);
11268 std::vector<bool> fetched(nbOfTuples,false);
11269 return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
11272 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg(std::vector<bool>& fetched, const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed)
11274 nbOfDepthPeelingPerformed=0;
11275 if(!seedBg || !seedEnd || !arrIn || !arrIndxIn)
11276 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg : some input pointer is NULL !");
11277 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11278 std::vector<bool> fetched2(nbOfTuples,false);
11280 for(const int *seedElt=seedBg;seedElt!=seedEnd;seedElt++,i++)
11282 if(*seedElt>=0 && *seedElt<nbOfTuples)
11283 { fetched[*seedElt]=true; fetched2[*seedElt]=true; }
11285 { 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()); }
11287 const int *arrInPtr=arrIn->getConstPointer();
11288 const int *arrIndxPtr=arrIndxIn->getConstPointer();
11289 int targetNbOfDepthPeeling=nbOfDepthPeeling!=-1?nbOfDepthPeeling:std::numeric_limits<int>::max();
11290 std::vector<int> idsToFetch1(seedBg,seedEnd);
11291 std::vector<int> idsToFetch2;
11292 std::vector<int> *idsToFetch=&idsToFetch1;
11293 std::vector<int> *idsToFetchOther=&idsToFetch2;
11294 while(!idsToFetch->empty() && nbOfDepthPeelingPerformed<targetNbOfDepthPeeling)
11296 for(std::vector<int>::const_iterator it=idsToFetch->begin();it!=idsToFetch->end();it++)
11297 for(const int *it2=arrInPtr+arrIndxPtr[*it];it2!=arrInPtr+arrIndxPtr[*it+1];it2++)
11299 { fetched[*it2]=true; fetched2[*it2]=true; idsToFetchOther->push_back(*it2); }
11300 std::swap(idsToFetch,idsToFetchOther);
11301 idsToFetchOther->clear();
11302 nbOfDepthPeelingPerformed++;
11304 int lgth=(int)std::count(fetched2.begin(),fetched2.end(),true);
11306 MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(lgth,1);
11307 int *retPtr=ret->getPointer();
11308 for(std::vector<bool>::const_iterator it=fetched2.begin();it!=fetched2.end();it++,i++)
11315 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11316 * 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
11317 * cellIds \b in [\b idsOfSelectBg, \b idsOfSelectEnd) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
11318 * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
11320 * \param [in] start begin of set of ids of the input extraction (included)
11321 * \param [in] end end of set of ids of the input extraction (excluded)
11322 * \param [in] step step of the set of ids in range mode.
11323 * \param [in] arrIn arr origin array from which the extraction will be done.
11324 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11325 * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
11326 * \param [in] srcArrIndex index array of \b srcArr
11327 * \param [out] arrOut the resulting array
11328 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11330 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx MEDCouplingUMesh::SetPartOfIndexedArrays
11332 void MEDCouplingUMesh::SetPartOfIndexedArraysSlice(int start, int end, int step, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11333 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
11334 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11336 if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11337 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSlice : presence of null pointer in input parameter !");
11338 MCAuto<DataArrayInt> arro=DataArrayInt::New();
11339 MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11340 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11342 const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11343 const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11344 int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSlice : ");
11346 for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
11348 if(it>=0 && it<nbOfTuples)
11349 offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[it+1]-arrIndxInPtr[it]);
11352 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
11353 throw INTERP_KERNEL::Exception(oss.str());
11356 srcArrIndexPtr=srcArrIndex->getConstPointer();
11357 arrIo->alloc(nbOfTuples+1,1);
11358 arro->alloc(arrIn->getNumberOfTuples()+offset,1);
11359 const int *arrInPtr=arrIn->getConstPointer();
11360 const int *srcArrPtr=srcArr->getConstPointer();
11361 int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
11362 int *arroPtr=arro->getPointer();
11363 for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
11365 int pos=DataArray::GetPosOfItemGivenBESRelativeNoThrow(ii,start,end,step);
11368 arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
11369 *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
11373 arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
11374 *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
11377 arrOut=arro.retn();
11378 arrIndexOut=arrIo.retn();
11382 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11383 * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
11385 * \param [in] start begin of set of ids of the input extraction (included)
11386 * \param [in] end end of set of ids of the input extraction (excluded)
11387 * \param [in] step step of the set of ids in range mode.
11388 * \param [in,out] arrInOut arr origin array from which the extraction will be done.
11389 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11390 * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
11391 * \param [in] srcArrIndex index array of \b srcArr
11393 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSlice MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
11395 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(int start, int end, int step, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
11396 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
11398 if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11399 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : presence of null pointer in input parameter !");
11400 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11401 const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11402 const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11403 int *arrInOutPtr=arrInOut->getPointer();
11404 const int *srcArrPtr=srcArr->getConstPointer();
11405 int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : ");
11407 for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
11409 if(it>=0 && it<nbOfTuples)
11411 if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[it+1]-arrIndxInPtr[it])
11412 std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[it]);
11415 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " id (idsOfSelectBg[" << i << "]) is " << it << " arrIndxIn[id+1]-arrIndxIn[id]!=srcArrIndex[pos+1]-srcArrIndex[pos] !";
11416 throw INTERP_KERNEL::Exception(oss.str());
11421 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
11422 throw INTERP_KERNEL::Exception(oss.str());
11428 * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
11429 * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
11430 * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
11431 * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
11432 * The sum of measure field of returned mesh is equal to the sum of measure field of this.
11434 * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
11436 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
11438 checkFullyDefined();
11439 int mdim=getMeshDimension();
11440 int spaceDim=getSpaceDimension();
11442 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
11443 std::vector<DataArrayInt *> partition=partitionBySpreadZone();
11444 std::vector< MCAuto<DataArrayInt> > partitionAuto; partitionAuto.reserve(partition.size());
11445 std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayInt> > >(partitionAuto));
11446 MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
11447 ret->setCoords(getCoords());
11448 ret->allocateCells((int)partition.size());
11450 for(std::vector<DataArrayInt *>::const_iterator it=partition.begin();it!=partition.end();it++)
11452 MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
11453 MCAuto<DataArrayInt> cell;
11457 cell=tmp->buildUnionOf2DMesh();
11460 cell=tmp->buildUnionOf3DMesh();
11463 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
11466 ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->getConstPointer()+1);
11469 ret->finishInsertingCells();
11474 * This method partitions \b this into contiguous zone.
11475 * This method only needs a well defined connectivity. Coordinates are not considered here.
11476 * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
11478 std::vector<DataArrayInt *> MEDCouplingUMesh::partitionBySpreadZone() const
11480 int nbOfCellsCur=getNumberOfCells();
11481 std::vector<DataArrayInt *> ret;
11482 if(nbOfCellsCur<=0)
11484 DataArrayInt *neigh=0,*neighI=0;
11485 computeNeighborsOfCells(neigh,neighI);
11486 MCAuto<DataArrayInt> neighAuto(neigh),neighIAuto(neighI);
11487 std::vector<bool> fetchedCells(nbOfCellsCur,false);
11488 std::vector< MCAuto<DataArrayInt> > ret2;
11490 while(seed<nbOfCellsCur)
11492 int nbOfPeelPerformed=0;
11493 ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,neigh,neighI,-1,nbOfPeelPerformed));
11494 seed=(int)std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false));
11496 for(std::vector< MCAuto<DataArrayInt> >::iterator it=ret2.begin();it!=ret2.end();it++)
11497 ret.push_back((*it).retn());
11502 * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
11503 * newly allocated DataArrayInt instance with 2 components ready to be interpreted as input of DataArrayInt::findRangeIdForEachTuple method.
11505 * \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.
11506 * \return a newly allocated DataArrayInt to be managed by the caller.
11507 * \throw In case of \a code has not the right format (typically of size 3*n)
11509 DataArrayInt *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<int>& code)
11511 MCAuto<DataArrayInt> ret=DataArrayInt::New();
11512 std::size_t nb=code.size()/3;
11513 if(code.size()%3!=0)
11514 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
11515 ret->alloc((int)nb,2);
11516 int *retPtr=ret->getPointer();
11517 for(std::size_t i=0;i<nb;i++,retPtr+=2)
11519 retPtr[0]=code[3*i+2];
11520 retPtr[1]=code[3*i+2]+code[3*i+1];
11526 * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
11527 * All cells in \a this are expected to be linear 3D cells.
11528 * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
11529 * It leads to an increase to number of cells.
11530 * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
11531 * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
11532 * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
11534 * \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.
11535 * For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
11536 * \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.
11537 * \param [out] n2oCells - A new instance of DataArrayInt holding, for each new cell,
11538 * an id of old cell producing it. The caller is to delete this array using
11539 * decrRef() as it is no more needed.
11540 * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
11542 * \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
11543 * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
11545 * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
11546 * \throw If \a this is not fully constituted with linear 3D cells.
11547 * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
11549 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayInt *& n2oCells, int& nbOfAdditionalPoints) const
11551 INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
11552 checkConnectivityFullyDefined();
11553 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
11554 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
11555 int nbOfCells(getNumberOfCells()),nbNodes(getNumberOfNodes());
11556 MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
11557 MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfCells,1);
11558 int *retPt(ret->getPointer());
11559 MCAuto<DataArrayInt> newConn(DataArrayInt::New()); newConn->alloc(0,1);
11560 MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
11561 const int *oldc(_nodal_connec->begin());
11562 const int *oldci(_nodal_connec_index->begin());
11563 const double *coords(_coords->begin());
11564 for(int i=0;i<nbOfCells;i++,oldci++,retPt++)
11566 std::vector<int> a; std::vector<double> b;
11567 INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
11568 std::size_t nbOfTet(a.size()/4); *retPt=(int)nbOfTet;
11569 const int *aa(&a[0]);
11572 for(std::vector<int>::iterator it=a.begin();it!=a.end();it++)
11574 *it=(-(*(it))-1+nbNodes);
11575 addPts->insertAtTheEnd(b.begin(),b.end());
11576 nbNodes+=(int)b.size()/3;
11578 for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
11579 newConn->insertAtTheEnd(aa,aa+4);
11581 if(!addPts->empty())
11583 addPts->rearrange(3);
11584 nbOfAdditionalPoints=addPts->getNumberOfTuples();
11585 addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
11586 ret0->setCoords(addPts);
11590 nbOfAdditionalPoints=0;
11591 ret0->setCoords(getCoords());
11593 ret0->setNodalConnectivity(newConn);
11595 ret->computeOffsetsFull();
11596 n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
11597 return ret0.retn();
11601 * 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).
11603 * \sa MEDCouplingUMesh::split2DCells
11605 void MEDCouplingUMesh::split2DCellsLinear(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI)
11607 checkConnectivityFullyDefined();
11608 int ncells(getNumberOfCells()),lgthToReach(getNodalConnectivityArrayLen()+subNodesInSeg->getNumberOfTuples());
11609 MCAuto<DataArrayInt> c(DataArrayInt::New()); c->alloc((std::size_t)lgthToReach);
11610 const int *subPtr(subNodesInSeg->begin()),*subIPtr(subNodesInSegI->begin()),*descPtr(desc->begin()),*descIPtr(descI->begin()),*oldConn(getNodalConnectivity()->begin());
11611 int *cPtr(c->getPointer()),*ciPtr(getNodalConnectivityIndex()->getPointer());
11612 int prevPosOfCi(ciPtr[0]);
11613 for(int i=0;i<ncells;i++,ciPtr++,descIPtr++)
11615 int offset(descIPtr[0]),sz(descIPtr[1]-descIPtr[0]),deltaSz(0);
11616 *cPtr++=(int)INTERP_KERNEL::NORM_POLYGON; *cPtr++=oldConn[prevPosOfCi+1];
11617 for(int j=0;j<sz;j++)
11619 int offset2(subIPtr[descPtr[offset+j]]),sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]);
11620 for(int k=0;k<sz2;k++)
11621 *cPtr++=subPtr[offset2+k];
11623 *cPtr++=oldConn[prevPosOfCi+j+2];
11626 prevPosOfCi=ciPtr[1];
11627 ciPtr[1]=ciPtr[0]+1+sz+deltaSz;//sz==old nb of nodes because (nb of subedges=nb of nodes for polygons)
11630 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCellsLinear : Some of edges to be split are orphan !");
11631 _nodal_connec->decrRef();
11632 _nodal_connec=c.retn(); _types.clear(); _types.insert(INTERP_KERNEL::NORM_POLYGON);
11635 int InternalAddPoint(const INTERP_KERNEL::Edge *e, int id, const double *coo, int startId, int endId, DataArrayDouble& addCoo, int& nodesCnter)
11641 int ret(nodesCnter++);
11643 e->getMiddleOfPoints(coo+2*startId,coo+2*endId,newPt);
11644 addCoo.insertAtTheEnd(newPt,newPt+2);
11649 int InternalAddPointOriented(const INTERP_KERNEL::Edge *e, int id, const double *coo, int startId, int endId, DataArrayDouble& addCoo, int& nodesCnter)
11655 int ret(nodesCnter++);
11657 e->getMiddleOfPointsOriented(coo+2*startId,coo+2*endId,newPt);
11658 addCoo.insertAtTheEnd(newPt,newPt+2);
11666 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)
11669 int trueStart(start>=0?start:nbOfEdges+start);
11670 tmp[0]=linOrArc?(int)INTERP_KERNEL::NORM_QPOLYG:(int)INTERP_KERNEL::NORM_POLYGON; tmp[1]=connBg[trueStart]; tmp[2]=connBg[stp];
11671 newConnOfCell->insertAtTheEnd(tmp,tmp+3);
11676 int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11677 InternalAddPointOriented(e,-1,coords,tmp[1],tmp[2],*appendedCoords,tmp2);
11678 middles.push_back(tmp3+offset);
11681 middles.push_back(connBg[trueStart+nbOfEdges]);
11685 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)
11687 int tmpSrt(newConnOfCell->back()),tmpEnd(connBg[stp]);
11688 newConnOfCell->pushBackSilent(tmpEnd);
11693 int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11694 InternalAddPointOriented(e,-1,coords,tmpSrt,tmpEnd,*appendedCoords,tmp2);
11695 middles.push_back(tmp3+offset);
11698 middles.push_back(connBg[start+nbOfEdges]);
11702 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)
11704 // only the quadratic point to deal with:
11709 int tmpSrt(connBg[start]),tmpEnd(connBg[stp]);
11710 int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11711 InternalAddPointOriented(e,-1,coords,tmpSrt,tmpEnd,*appendedCoords,tmp2);
11712 middles.push_back(tmp3+offset);
11715 middles.push_back(connBg[start+nbOfEdges]);
11722 * 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 ) .
11723 * \a appendedCoords is a DataArrayDouble instance with number of components equal to one (even if the items are pushed by pair).
11725 bool MEDCouplingUMesh::Colinearize2DCell(const double *coords, const int *connBg, const int *connEnd, int offset, DataArrayInt *newConnOfCell, DataArrayDouble *appendedCoords)
11727 std::size_t sz(std::distance(connBg,connEnd));
11728 if(sz<3)//3 because 2+1(for the cell type) and 2 is the minimal number of edges of 2D cell.
11729 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Colinearize2DCell : the input cell has invalid format !");
11731 INTERP_KERNEL::AutoPtr<int> tmpConn(new int[sz]);
11732 const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connBg[0]));
11733 unsigned nbs(cm.getNumberOfSons2(connBg+1,sz));
11734 unsigned nbOfHit(0); // number of fusions operated
11735 int posBaseElt(0),posEndElt(0),nbOfTurn(0);
11736 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
11737 INTERP_KERNEL::NormalizedCellType typeOfSon;
11738 std::vector<int> middles;
11740 for(;(nbOfTurn+nbOfHit)<nbs;nbOfTurn++)
11742 cm.fillSonCellNodalConnectivity2(posBaseElt,connBg+1,sz,tmpConn,typeOfSon);
11743 std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
11744 INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11745 posEndElt = posBaseElt+1;
11747 // Look backward first: are the final edges of the cells colinear with the first ones?
11748 // This initializes posBaseElt.
11751 for(unsigned i=1;i<nbs && nbOfHit<maxNbOfHit;i++) // 2nd condition is to avoid ending with a cell wih one single edge
11753 cm.fillSonCellNodalConnectivity2(nbs-i,connBg+1,sz,tmpConn,typeOfSon);
11754 INTERP_KERNEL::Edge *eCand(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11755 INTERP_KERNEL::EdgeIntersector *eint(INTERP_KERNEL::Edge::BuildIntersectorWith(e,eCand));
11756 bool isColinear=eint->areColinears();
11769 // Now move forward:
11770 const unsigned fwdStart = (nbOfTurn == 0 ? 0 : posBaseElt); // the first element to be inspected going forward
11771 for(unsigned j=fwdStart+1;j<nbs && nbOfHit<maxNbOfHit;j++) // 2nd condition is to avoid ending with a cell wih one single edge
11773 cm.fillSonCellNodalConnectivity2((int)j,connBg+1,sz,tmpConn,typeOfSon); // get edge #j's connectivity
11774 INTERP_KERNEL::Edge *eCand(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11775 INTERP_KERNEL::EdgeIntersector *eint(INTERP_KERNEL::Edge::BuildIntersectorWith(e,eCand));
11776 bool isColinear(eint->areColinears());
11788 //push [posBaseElt,posEndElt) in newConnOfCell using e
11789 // 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!
11791 // at the begining of the connectivity (insert type)
11792 EnterTheResultOf2DCellFirst(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
11793 else if((nbOfHit+nbOfTurn) != (nbs-1))
11795 EnterTheResultOf2DCellMiddle(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
11796 if ((nbOfHit+nbOfTurn) == (nbs-1))
11797 // at the end (only quad points to deal with)
11798 EnterTheResultOf2DCellEnd(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
11799 posBaseElt=posEndElt;
11802 if(!middles.empty())
11803 newConnOfCell->insertAtTheEnd(middles.begin(),middles.end());
11808 * It is the quadratic part of MEDCouplingUMesh::split2DCells. Here some additionnal nodes can be added at the end of coordinates array object.
11810 * \return int - the number of new nodes created.
11811 * \sa MEDCouplingUMesh::split2DCells
11813 int MEDCouplingUMesh::split2DCellsQuadratic(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *mid, const DataArrayInt *midI)
11815 checkConsistencyLight();
11816 int ncells(getNumberOfCells()),lgthToReach(getNodalConnectivityArrayLen()+2*subNodesInSeg->getNumberOfTuples()),nodesCnt(getNumberOfNodes());
11817 MCAuto<DataArrayInt> c(DataArrayInt::New()); c->alloc((std::size_t)lgthToReach);
11818 MCAuto<DataArrayDouble> addCoo(DataArrayDouble::New()); addCoo->alloc(0,1);
11819 const int *subPtr(subNodesInSeg->begin()),*subIPtr(subNodesInSegI->begin()),*descPtr(desc->begin()),*descIPtr(descI->begin()),*oldConn(getNodalConnectivity()->begin());
11820 const int *midPtr(mid->begin()),*midIPtr(midI->begin());
11821 const double *oldCoordsPtr(getCoords()->begin());
11822 int *cPtr(c->getPointer()),*ciPtr(getNodalConnectivityIndex()->getPointer());
11823 int prevPosOfCi(ciPtr[0]);
11824 for(int i=0;i<ncells;i++,ciPtr++,descIPtr++)
11826 int offset(descIPtr[0]),sz(descIPtr[1]-descIPtr[0]),deltaSz(sz);
11827 for(int j=0;j<sz;j++)
11828 { int sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]); deltaSz+=sz2; }
11829 *cPtr++=(int)INTERP_KERNEL::NORM_QPOLYG; cPtr[0]=oldConn[prevPosOfCi+1];
11830 for(int j=0;j<sz;j++)//loop over subedges of oldConn
11832 int offset2(subIPtr[descPtr[offset+j]]),sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]),offset3(midIPtr[descPtr[offset+j]]);
11836 cPtr[1]=oldConn[prevPosOfCi+2+j];
11837 cPtr[deltaSz]=oldConn[prevPosOfCi+1+j+sz]; cPtr++;
11840 std::vector<INTERP_KERNEL::Node *> ns(3);
11841 ns[0]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+j]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+j]+1]);
11842 ns[1]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+(1+j)%sz]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+(1+j)%sz]+1]);
11843 ns[2]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+sz+j]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+sz+j]+1]);
11844 MCAuto<INTERP_KERNEL::Edge> e(INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(ns));
11845 for(int k=0;k<sz2;k++)//loop over subsplit of current subedge
11847 cPtr[1]=subPtr[offset2+k];
11848 cPtr[deltaSz]=InternalAddPoint(e,midPtr[offset3+k],oldCoordsPtr,cPtr[0],cPtr[1],*addCoo,nodesCnt); cPtr++;
11850 int tmpEnd(oldConn[prevPosOfCi+1+(j+1)%sz]);
11852 { cPtr[1]=tmpEnd; }
11853 cPtr[deltaSz]=InternalAddPoint(e,midPtr[offset3+sz2],oldCoordsPtr,cPtr[0],tmpEnd,*addCoo,nodesCnt); cPtr++;
11855 prevPosOfCi=ciPtr[1]; cPtr+=deltaSz;
11856 ciPtr[1]=ciPtr[0]+1+2*deltaSz;//sz==old nb of nodes because (nb of subedges=nb of nodes for polygons)
11859 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCellsQuadratic : Some of edges to be split are orphan !");
11860 _nodal_connec->decrRef();
11861 _nodal_connec=c.retn(); _types.clear(); _types.insert(INTERP_KERNEL::NORM_QPOLYG);
11862 addCoo->rearrange(2);
11863 MCAuto<DataArrayDouble> coo(DataArrayDouble::Aggregate(getCoords(),addCoo));//info are copied from getCoords() by using Aggregate
11865 return addCoo->getNumberOfTuples();
11868 void MEDCouplingUMesh::ComputeAllTypesInternal(std::set<INTERP_KERNEL::NormalizedCellType>& types, const DataArrayInt *nodalConnec, const DataArrayInt *nodalConnecIndex)
11870 if(nodalConnec && nodalConnecIndex)
11873 const int *conn(nodalConnec->getConstPointer()),*connIndex(nodalConnecIndex->getConstPointer());
11874 int nbOfElem(nodalConnecIndex->getNbOfElems()-1);
11876 for(const int *pt=connIndex;pt!=connIndex+nbOfElem;pt++)
11877 types.insert((INTERP_KERNEL::NormalizedCellType)conn[*pt]);
11881 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
11882 _own_cell(true),_cell_id(-1),_nb_cell(0)
11887 _nb_cell=mesh->getNumberOfCells();
11891 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
11899 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_cell(itc),
11900 _own_cell(false),_cell_id(bg-1),
11907 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
11910 if(_cell_id<_nb_cell)
11919 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
11925 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
11927 return new MEDCouplingUMeshCellByTypeIterator(_mesh);
11930 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
11936 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh, INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_type(type),
11944 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
11950 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
11955 int MEDCouplingUMeshCellEntry::getNumberOfElems() const
11960 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
11962 return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
11965 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
11970 _nb_cell=mesh->getNumberOfCells();
11974 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
11981 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
11983 const int *c=_mesh->getNodalConnectivity()->getConstPointer();
11984 const int *ci=_mesh->getNodalConnectivityIndex()->getConstPointer();
11985 if(_cell_id<_nb_cell)
11987 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
11988 int nbOfElems=(int)std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type)));
11989 int startId=_cell_id;
11990 _cell_id+=nbOfElems;
11991 return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
11997 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
12001 _conn=mesh->getNodalConnectivity()->getPointer();
12002 _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
12006 void MEDCouplingUMeshCell::next()
12008 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
12013 _conn_lgth=_conn_indx[1]-_conn_indx[0];
12016 std::string MEDCouplingUMeshCell::repr() const
12018 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
12020 std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
12022 std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<int>(oss," "));
12026 return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
12029 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
12031 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
12032 return (INTERP_KERNEL::NormalizedCellType)_conn[0];
12034 return INTERP_KERNEL::NORM_ERROR;
12037 const int *MEDCouplingUMeshCell::getAllConn(int& lgth) const
12040 if(_conn_lgth!=NOTICABLE_FIRST_VAL)