1 // Copyright (C) 2007-2012 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.
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 "MEDCouplingMemArray.txx"
23 #include "MEDCouplingFieldDouble.hxx"
24 #include "CellModel.hxx"
25 #include "VolSurfUser.txx"
26 #include "InterpolationUtils.hxx"
27 #include "PointLocatorAlgos.txx"
29 #include "DirectedBoundingBox.hxx"
30 #include "InterpKernelMeshQuality.hxx"
31 #include "InterpKernelCellSimplify.hxx"
32 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
33 #include "MEDCouplingAutoRefCountObjectPtr.hxx"
34 #include "InterpKernelAutoPtr.hxx"
35 #include "InterpKernelGeo2DNode.hxx"
36 #include "InterpKernelGeo2DEdgeLin.hxx"
37 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
38 #include "InterpKernelGeo2DQuadraticPolygon.hxx"
47 using namespace ParaMEDMEM;
49 const char MEDCouplingUMesh::PART_OF_NAME[]="PartOf_";
51 double MEDCouplingUMesh::EPS_FOR_POLYH_ORIENTATION=1.e-14;
53 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 };
55 MEDCouplingUMesh *MEDCouplingUMesh::New()
57 return new MEDCouplingUMesh;
60 MEDCouplingUMesh *MEDCouplingUMesh::New(const char *meshName, int meshDim)
62 MEDCouplingUMesh *ret=new MEDCouplingUMesh;
63 ret->setName(meshName);
64 ret->setMeshDimension(meshDim);
68 MEDCouplingMesh *MEDCouplingUMesh::deepCpy() const
73 MEDCouplingUMesh *MEDCouplingUMesh::clone(bool recDeepCpy) const
75 return new MEDCouplingUMesh(*this,recDeepCpy);
78 void MEDCouplingUMesh::updateTime() const
80 MEDCouplingPointSet::updateTime();
83 updateTimeWith(*_nodal_connec);
85 if(_nodal_connec_index)
87 updateTimeWith(*_nodal_connec_index);
91 MEDCouplingUMesh::MEDCouplingUMesh():_iterator(-1),_mesh_dim(-2),
92 _nodal_connec(0),_nodal_connec_index(0)
97 * This method checks that this is correctly designed. For example le coordinates are set, nodal connectivity.
98 * When this method returns without throwing any exception, 'this' is expected to be writable, exchangeable and to be
99 * available for most of algorithm. When a mesh has been constructed from scratch it is a good habits to call this method to check
100 * that all is in order in 'this'.
102 void MEDCouplingUMesh::checkCoherency() const throw(INTERP_KERNEL::Exception)
105 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
106 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
108 if((int)INTERP_KERNEL::CellModel::GetCellModel(*iter).getDimension()!=_mesh_dim)
110 std::ostringstream message;
111 message << "Mesh invalid because dimension is " << _mesh_dim << " and there is presence of cell(s) with type " << (*iter);
112 throw INTERP_KERNEL::Exception(message.str().c_str());
117 if(_nodal_connec->getNumberOfComponents()!=1)
118 throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to be with number of components set to one !");
119 if(_nodal_connec->getInfoOnComponent(0)!="")
120 throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to have no info on its single component !");
122 if(_nodal_connec_index)
124 if(_nodal_connec_index->getNumberOfComponents()!=1)
125 throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to be with number of components set to one !");
126 if(_nodal_connec_index->getInfoOnComponent(0)!="")
127 throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to have no info on its single component !");
131 throw INTERP_KERNEL::Exception("It appears that finishInsertingCells method has not been invoked after a insertNextCell session !");
136 * This method performs deeper checking in 'this' than MEDCouplingUMesh::checkCoherency does.
137 * So this method is more time-consuming. This method checks that nodal connectivity points to valid node ids.
138 * No geometrical aspects are checked here. These aspects are done in MEDCouplingUMesh::checkCoherency2.
140 void MEDCouplingUMesh::checkCoherency1(double eps) const throw(INTERP_KERNEL::Exception)
145 int meshDim=getMeshDimension();
146 int nbOfNodes=getNumberOfNodes();
147 int nbOfCells=getNumberOfCells();
148 const int *ptr=_nodal_connec->getConstPointer();
149 const int *ptrI=_nodal_connec_index->getConstPointer();
150 for(int i=0;i<nbOfCells;i++)
152 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)ptr[ptrI[i]]);
153 if((int)cm.getDimension()!=meshDim)
155 std::ostringstream oss;
156 oss << "MEDCouplingUMesh::checkCoherency1 : cell << #" << i<< " with type Type " << cm.getRepr() << " in 'this' whereas meshdim == " << meshDim << " !";
157 throw INTERP_KERNEL::Exception(oss.str().c_str());
159 int nbOfNodesInCell=ptrI[i+1]-ptrI[i]-1;
161 if(nbOfNodesInCell!=(int)cm.getNumberOfNodes())
163 std::ostringstream oss;
164 oss << "MEDCouplingUMesh::checkCoherency1 : cell #" << i << " with static Type '" << cm.getRepr() << "' has " << cm.getNumberOfNodes();
165 oss << " nodes whereas in connectivity there is " << nbOfNodesInCell << " nodes ! Looks very bad !";
166 throw INTERP_KERNEL::Exception(oss.str().c_str());
168 for(const int *w=ptr+ptrI[i]+1;w!=ptr+ptrI[i+1];w++)
173 if(nodeId>=nbOfNodes)
175 std::ostringstream oss; oss << "Cell #" << i << " is consituted of node #" << nodeId << " whereas there are only " << nbOfNodes << " nodes !";
176 throw INTERP_KERNEL::Exception(oss.str().c_str());
181 std::ostringstream oss; oss << "Cell #" << i << " is consituted of node #" << nodeId << " in connectivity ! sounds bad !";
182 throw INTERP_KERNEL::Exception(oss.str().c_str());
186 if((INTERP_KERNEL::NormalizedCellType)(ptr[ptrI[i]])!=INTERP_KERNEL::NORM_POLYHED)
188 std::ostringstream oss; oss << "Cell #" << i << " is consituted of node #-1 in connectivity ! sounds bad !";
189 throw INTERP_KERNEL::Exception(oss.str().c_str());
196 void MEDCouplingUMesh::checkCoherency2(double eps) const throw(INTERP_KERNEL::Exception)
198 checkCoherency1(eps);
201 void MEDCouplingUMesh::setMeshDimension(int meshDim)
204 throw INTERP_KERNEL::Exception("Invalid meshDim specified ! Must be greater or equal to -1 !");
209 void MEDCouplingUMesh::allocateCells(int nbOfCells)
211 if(_nodal_connec_index)
213 _nodal_connec_index->decrRef();
217 _nodal_connec->decrRef();
220 _nodal_connec_index=DataArrayInt::New();
221 _nodal_connec_index->alloc(nbOfCells+1,1);
222 int *pt=_nodal_connec_index->getPointer();
224 _nodal_connec=DataArrayInt::New();
225 _nodal_connec->alloc(2*nbOfCells,1);
232 * Appends a cell in connectivity array.
233 * @param type type of cell to add.
234 * @param size number of nodes constituting this cell.
235 * @param nodalConnOfCell the connectivity of the cell to add.
237 void MEDCouplingUMesh::insertNextCell(INTERP_KERNEL::NormalizedCellType type, int size, const int *nodalConnOfCell) throw(INTERP_KERNEL::Exception)
239 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
240 if(_nodal_connec_index==0)
241 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::insertNextCell : nodal connectivity not set ! invoke allocateCells before calling insertNextCell !");
242 if((int)cm.getDimension()==_mesh_dim)
244 int nbOfElems=_nodal_connec_index->getNbOfElems()-1;
245 if(_iterator>=nbOfElems)
246 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::insertNextCell : allocation of cells was wide enough ! Call insertNextCell with higher value or call finishInsertingCells !");
247 int *pt=_nodal_connec_index->getPointer();
248 int idx=pt[_iterator];
250 _nodal_connec->writeOnPlace(idx,type,nodalConnOfCell,size);
252 pt[++_iterator]=idx+size+1;
256 std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : cell type " << cm.getRepr() << " has a dimension " << cm.getDimension();
257 oss << " whereas Mesh Dimension of current UMesh instance is set to " << _mesh_dim << " ! Please invoke \"setMeshDimension\" method before or invoke ";
258 oss << "\"MEDCouplingUMesh::New\" static method with 2 parameters name and meshDimension !";
259 throw INTERP_KERNEL::Exception(oss.str().c_str());
264 * Method to be called to cloture the insertion of cells using this->insertNextCell.
266 void MEDCouplingUMesh::finishInsertingCells()
268 const int *pt=_nodal_connec_index->getConstPointer();
269 int idx=pt[_iterator];
271 _nodal_connec->reAlloc(idx);
272 _nodal_connec_index->reAlloc(_iterator+1);
274 _nodal_connec->declareAsNew();
275 _nodal_connec_index->declareAsNew();
280 * Entry point for iteration over cells of this. Warning the returned cell iterator should be deallocated.
281 * Useful for python users.
283 MEDCouplingUMeshCellIterator *MEDCouplingUMesh::cellIterator()
285 return new MEDCouplingUMeshCellIterator(this);
289 * Entry point for iteration over cells groups geo types per geotypes. Warning the returned cell iterator should be deallocated.
290 * If 'this' is not so that that cells are grouped by geo types this method will throw an exception.
291 * In this case MEDCouplingUMesh::sortCellsInMEDFileFrmt or MEDCouplingUMesh::rearrange2ConsecutiveCellTypes methods for example can be called before invoking this method.
292 * Useful for python users.
294 MEDCouplingUMeshCellByTypeEntry *MEDCouplingUMesh::cellsByType() throw(INTERP_KERNEL::Exception)
296 if(!checkConsecutiveCellTypes())
297 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::cellsByType : this mesh is not sorted by type !");
298 return new MEDCouplingUMeshCellByTypeEntry(this);
301 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypes() const
307 * This method is a method that compares 'this' and 'other'.
308 * This method compares \b all attributes, even names and component names.
310 bool MEDCouplingUMesh::isEqualIfNotWhy(const MEDCouplingMesh *other, double prec, std::string& reason) const throw(INTERP_KERNEL::Exception)
313 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isEqualIfNotWhy : input other pointer is null !");
314 std::ostringstream oss; oss.precision(15);
315 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
318 reason="mesh given in input is not castable in MEDCouplingUMesh !";
321 if(!MEDCouplingPointSet::isEqualIfNotWhy(other,prec,reason))
323 if(_mesh_dim!=otherC->_mesh_dim)
325 oss << "umesh dimension mismatch : this mesh dimension=" << _mesh_dim << " other mesh dimension=" << otherC->_mesh_dim;
329 if(_types!=otherC->_types)
331 oss << "umesh geometric type mismatch :\nThis geometric types are :";
332 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
333 { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
334 oss << "\nOther geometric types are :";
335 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=otherC->_types.begin();iter!=otherC->_types.end();iter++)
336 { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
340 if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
341 if(_nodal_connec==0 || otherC->_nodal_connec==0)
343 reason="Only one UMesh between the two this and other has its nodal connectivity DataArrayInt defined !";
346 if(_nodal_connec!=otherC->_nodal_connec)
347 if(!_nodal_connec->isEqualIfNotWhy(*otherC->_nodal_connec,reason))
349 reason.insert(0,"Nodal connectivity DataArrayInt differ : ");
352 if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
353 if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
355 reason="Only one UMesh between the two this and other has its nodal connectivity index DataArrayInt defined !";
358 if(_nodal_connec_index!=otherC->_nodal_connec_index)
359 if(!_nodal_connec_index->isEqualIfNotWhy(*otherC->_nodal_connec_index,reason))
361 reason.insert(0,"Nodal connectivity index DataArrayInt differ : ");
367 bool MEDCouplingUMesh::isEqualWithoutConsideringStr(const MEDCouplingMesh *other, double prec) const
369 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
372 if(!MEDCouplingPointSet::isEqualWithoutConsideringStr(other,prec))
374 if(_mesh_dim!=otherC->_mesh_dim)
376 if(_types!=otherC->_types)
378 if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
379 if(_nodal_connec==0 || otherC->_nodal_connec==0)
381 if(_nodal_connec!=otherC->_nodal_connec)
382 if(!_nodal_connec->isEqualWithoutConsideringStr(*otherC->_nodal_connec))
384 if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
385 if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
387 if(_nodal_connec_index!=otherC->_nodal_connec_index)
388 if(!_nodal_connec_index->isEqualWithoutConsideringStr(*otherC->_nodal_connec_index))
394 * This method looks if 'this' and 'other' are geometrically equivalent that is to say if each cell in 'other' correspond to one cell and only one
395 * in 'this' is found regarding 'prec' parameter and 'cellCompPol' parameter.
397 * In case of success cellCor and nodeCor are informed both.
398 * @param cellCompPol values are described in MEDCouplingUMesh::zipConnectivityTraducer method.
399 * @param cellCor output array giving the correspondance of cells from 'other' to 'this'.
400 * @param nodeCor output array giving the correspondance of nodes from 'other' to 'this'.
402 void MEDCouplingUMesh::checkDeepEquivalWith(const MEDCouplingMesh *other, int cellCompPol, double prec,
403 DataArrayInt *&cellCor, DataArrayInt *&nodeCor) const throw(INTERP_KERNEL::Exception)
405 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
407 throw INTERP_KERNEL::Exception("checkDeepEquivalWith : Two meshes are not not unstructured !");
408 MEDCouplingMesh::checkFastEquivalWith(other,prec);
409 if(_types!=otherC->_types)
410 throw INTERP_KERNEL::Exception("checkDeepEquivalWith : Types are not equal !");
411 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m=MergeUMeshes(this,otherC);
414 int oldNbOfNodes=getNumberOfNodes();
415 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> da=m->buildPermArrayForMergeNode(prec,oldNbOfNodes,areNodesMerged,newNbOfNodes);
418 throw INTERP_KERNEL::Exception("checkDeepEquivalWith : Nodes are incompatible ! ");
419 const int *pt=std::find_if(da->getConstPointer()+oldNbOfNodes,da->getConstPointer()+da->getNbOfElems(),std::bind2nd(std::greater<int>(),oldNbOfNodes-1));
420 if(pt!=da->getConstPointer()+da->getNbOfElems())
421 throw INTERP_KERNEL::Exception("checkDeepEquivalWith : some nodes in other are not in this !");
422 m->renumberNodes(da->getConstPointer(),newNbOfNodes);
424 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> nodeCor2=da->substr(oldNbOfNodes);
425 da=m->mergeNodes(prec,areNodesMerged,newNbOfNodes);
428 da=m->zipConnectivityTraducer(cellCompPol);
429 int maxId=*std::max_element(da->getConstPointer(),da->getConstPointer()+getNumberOfCells());
430 pt=std::find_if(da->getConstPointer()+getNumberOfCells(),da->getConstPointer()+da->getNbOfElems(),std::bind2nd(std::greater<int>(),maxId));
431 if(pt!=da->getConstPointer()+da->getNbOfElems())
432 throw INTERP_KERNEL::Exception("checkDeepEquivalWith : some cells in other are not in this !");
433 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cellCor2=DataArrayInt::New();
434 cellCor2->alloc(otherC->getNumberOfCells(),1);
435 std::copy(da->getConstPointer()+getNumberOfCells(),da->getConstPointer()+da->getNbOfElems(),cellCor2->getPointer());
436 bool nident=nodeCor2->isIdentity();
437 bool cident=cellCor2->isIdentity();
438 if(!nident) { nodeCor=nodeCor2; nodeCor2->incrRef(); } else nodeCor=0;
439 if(!cident) { cellCor=cellCor2; cellCor2->incrRef(); } else cellCor=0;
443 * This method looks if 'this' and 'other' are geometrically equivalent that is to say if each cell in 'other' correspond to one cell and only one
444 * in 'this' is found regarding 'prec' parameter and 'cellCompPol' parameter. The difference with MEDCouplingUMesh::checkDeepEquivalWith method is that
445 * coordinates of 'this' and 'other' are expected to be the same. If not an exception will be thrown.
446 * This method is close to MEDCouplingUMesh::areCellsIncludedIn except that this method throws exception !
448 * In case of success cellCor are informed both.
449 * @param cellCompPol values are described in MEDCouplingUMesh::zipConnectivityTraducer method.
450 * @param cellCor output array giving the correspondance of cells from 'other' to 'this'.
452 void MEDCouplingUMesh::checkDeepEquivalOnSameNodesWith(const MEDCouplingMesh *other, int cellCompPol, double prec,
453 DataArrayInt *&cellCor) const throw(INTERP_KERNEL::Exception)
455 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
457 throw INTERP_KERNEL::Exception("checkDeepEquivalOnSameNodesWith : Two meshes are not not unstructured !");
458 MEDCouplingMesh::checkFastEquivalWith(other,prec);
459 if(_types!=otherC->_types)
460 throw INTERP_KERNEL::Exception("checkDeepEquivalOnSameNodesWith : Types are not equal !");
461 if(_coords!=otherC->_coords)
462 throw INTERP_KERNEL::Exception("checkDeepEquivalOnSameNodesWith : meshes do not share the same coordinates ! Use tryToShareSameCoordinates or call checkDeepEquivalWith !");
463 std::vector<const MEDCouplingUMesh *> ms(2);
466 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m=MergeUMeshesOnSameCoords(ms);
467 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> da=m->zipConnectivityTraducer(cellCompPol);
468 int maxId=*std::max_element(da->getConstPointer(),da->getConstPointer()+getNumberOfCells());
469 const int *pt=std::find_if(da->getConstPointer()+getNumberOfCells(),da->getConstPointer()+da->getNbOfElems(),std::bind2nd(std::greater<int>(),maxId));
470 if(pt!=da->getConstPointer()+da->getNbOfElems())
472 throw INTERP_KERNEL::Exception("checkDeepEquivalOnSameNodesWith : some cells in other are not in this !");
474 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cellCor2=DataArrayInt::New();
475 cellCor2->alloc(otherC->getNumberOfCells(),1);
476 std::copy(da->getConstPointer()+getNumberOfCells(),da->getConstPointer()+da->getNbOfElems(),cellCor2->getPointer());
477 if(!cellCor2->isIdentity()) { cellCor=cellCor2; cellCor2->incrRef(); } else cellCor=0;
481 * This method checks fastly that 'this' and 'other' are equal.
483 void MEDCouplingUMesh::checkFastEquivalWith(const MEDCouplingMesh *other, double prec) const throw(INTERP_KERNEL::Exception)
485 const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
487 throw INTERP_KERNEL::Exception("checkFastEquivalWith : Two meshes are not not unstructured !");
488 MEDCouplingPointSet::checkFastEquivalWith(other,prec);
489 int nbOfCells=getNumberOfCells();
493 status&=areCellsFrom2MeshEqual(otherC,0,prec);
494 status&=areCellsFrom2MeshEqual(otherC,nbOfCells/2,prec);
495 status&=areCellsFrom2MeshEqual(otherC,nbOfCells-1,prec);
497 throw INTERP_KERNEL::Exception("checkFastEquivalWith : Two meshes are not equal because on 3 test cells some difference have been detected !");
501 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
502 * For speed reasons no check of this will be done.
504 void MEDCouplingUMesh::getReverseNodalConnectivity(DataArrayInt *revNodal, DataArrayInt *revNodalIndx) const throw(INTERP_KERNEL::Exception)
507 int nbOfNodes=getNumberOfNodes();
508 int *revNodalIndxPtr=new int[nbOfNodes+1];
509 revNodalIndx->useArray(revNodalIndxPtr,true,CPP_DEALLOC,nbOfNodes+1,1);
510 std::fill(revNodalIndxPtr,revNodalIndxPtr+nbOfNodes+1,0);
511 const int *conn=_nodal_connec->getConstPointer();
512 const int *connIndex=_nodal_connec_index->getConstPointer();
513 int nbOfCells=getNumberOfCells();
514 int nbOfEltsInRevNodal=0;
515 for(int eltId=0;eltId<nbOfCells;eltId++)
517 const int *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
518 const int *endNdlConnOfCurCell=conn+connIndex[eltId+1];
519 for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
520 if(*iter>=0)//for polyhedrons
522 nbOfEltsInRevNodal++;
523 revNodalIndxPtr[(*iter)+1]++;
526 std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<int>());
527 int *revNodalPtr=new int[nbOfEltsInRevNodal];
528 revNodal->useArray(revNodalPtr,true,CPP_DEALLOC,nbOfEltsInRevNodal,1);
529 std::fill(revNodalPtr,revNodalPtr+nbOfEltsInRevNodal,-1);
530 for(int eltId=0;eltId<nbOfCells;eltId++)
532 const int *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
533 const int *endNdlConnOfCurCell=conn+connIndex[eltId+1];
534 for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
535 if(*iter>=0)//for polyhedrons
536 *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind2nd(std::equal_to<int>(),-1))=eltId;
542 int MEDCouplingFastNbrer(int id, unsigned nb, const INTERP_KERNEL::CellModel& cm, bool compute, const int *conn1, const int *conn2)
547 int MEDCouplingOrientationSensitiveNbrer(int id, unsigned nb, const INTERP_KERNEL::CellModel& cm, bool compute, const int *conn1, const int *conn2)
553 if(cm.getOrientationStatus(nb,conn1,conn2))
563 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
564 * For speed reasons no check of this will be done.
565 * Given 'this' with spacedim equal to s and meshdim equal to p, this method returns a new allocated mesh
566 * lying on the same coordinates than 'this' and having a meshdim equal to p-1.
567 * The algorithm to compute this p-1 mesh is the following :
568 * For each cell in 'this' it splits into p-1 elements.
569 * If this p-1 element does not already exists it is appended to the returned mesh
570 * If this p-1 element already exists, it is not appended.
571 * This method returns or 4 arrays plus the returned mesh.
572 * 'desc' and 'descIndx' are the descending connectivity. These 2 arrays tell for each cell in 'this', to wich p-1 dimension cell in returned mesh it refers.
573 * For a cell with a cellid c in 'this' it is constituted of cells in [desc+descIndx[c],desc+descIndex[c+1])
575 * Reversely 'revDesc' and 'revDescIndx' are the reverse descending connectivity. These 2 arrays tell for each cell in returned mesh, to wich cell in 'this' it refers.
576 * For a cell with a cellid d in returned p-1 mesh it is shared by the following cells in 'this' [revDesc+revDescIndx[d],revDesc+revDescIndx[d+1])
578 * \warning This method returns a mesh whose geometric type order in are \b not sorted.
579 * In view of the MED file writing, a renumbering of cells in returned mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
581 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const throw(INTERP_KERNEL::Exception)
583 return buildDescendingConnectivityGen(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
587 * WARNING this method do the assumption that connectivity lies on the coordinates set.
588 * For speed reasons no check of this will be done.
589 * This method differs from MEDCouplingUMesh::buildDescendingConnectivity method in that 'desc' is in different format.
590 * This method is more precise because it returns in descending connectivity giving the direction. If value is positive the n-1 dim element is taken in the same direction,
591 * if it is in the opposite direction it is retrieved negative. So the problem is for elemt #0 in C convention. That's why this method is the only one that retrieves
592 * an array in relative "FORTRAN" mode.
594 * \warning This method returns a mesh whose geometric type order in are \b not sorted.
595 * In view of the MED file writing, a renumbering of cells in returned mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
597 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const throw(INTERP_KERNEL::Exception)
599 return buildDescendingConnectivityGen(desc,descIndx,revDesc,revDescIndx,MEDCouplingOrientationSensitiveNbrer);
603 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
604 * For speed reasons no check of this will be done. This method calls MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
605 * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities are considered.
606 * The a cell with id 'cellId' its neighbors are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
608 * \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
609 * parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
610 * \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.
612 void MEDCouplingUMesh::computeNeighborsOfCells(DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx) const throw(INTERP_KERNEL::Exception)
614 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> desc=DataArrayInt::New();
615 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> descIndx=DataArrayInt::New();
616 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revDesc=DataArrayInt::New();
617 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revDescIndx=DataArrayInt::New();
618 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
620 ComputeNeighborsOfCellsAdv(desc,descIndx,revDesc,revDescIndx,neighbors,neighborsIndx);
624 * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm of MEDCouplingUMesh::computeNeighborsOfCells.
625 * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is typically the case to extract a set a neighbours,
626 * excluding a set of meshdim-1 cells in input descending connectivity.
627 * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx input params are the result of MEDCouplingUMesh::buildDescendingConnectivity.
628 * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities are considered.
629 * The a cell with id 'cellId' its neighbors are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
631 * \param [in] desc descending connectivity array.
632 * \param [in] descIndx descending connectivity index array used to walk through \b desc.
633 * \param [in] revDesc reverse descending connectivity array.
634 * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc.
635 * \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
636 * parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
637 * \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.
639 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayInt *desc, const DataArrayInt *descIndx, const DataArrayInt *revDesc, const DataArrayInt *revDescIndx,
640 DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx) throw(INTERP_KERNEL::Exception)
642 if(!desc || !descIndx || !revDesc || !revDescIndx)
643 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
644 const int *descPtr=desc->getConstPointer();
645 const int *descIPtr=descIndx->getConstPointer();
646 const int *revDescPtr=revDesc->getConstPointer();
647 const int *revDescIPtr=revDescIndx->getConstPointer();
649 int nbCells=descIndx->getNumberOfTuples()-1;
650 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> out0=DataArrayInt::New();
651 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> out1=DataArrayInt::New(); out1->alloc(nbCells+1,1);
652 int *out1Ptr=out1->getPointer();
654 std::vector<int> out0v;
655 out0v.reserve(desc->getNumberOfTuples());
656 for(int i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
658 for(const int *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
660 std::set<int> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
662 out0v.insert(out0v.end(),s.begin(),s.end());
664 *out1Ptr=out0v.size();
666 out0->alloc((int)out0v.size(),1);
667 std::copy(out0v.begin(),out0v.end(),out0->getPointer());
668 neighbors=out0; out0->incrRef();
669 neighborsIndx=out1; out1->incrRef();
675 * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
676 * For speed reasons no check of this will be done.
678 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivityGen(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx, DimM1DescNbrer nbrer) const throw(INTERP_KERNEL::Exception)
680 checkConnectivityFullyDefined();
681 int nbOfCells=getNumberOfCells();
682 int nbOfNodes=getNumberOfNodes();
683 const int *conn=_nodal_connec->getConstPointer();
684 const int *connIndex=_nodal_connec_index->getConstPointer();
685 std::vector< std::vector<int> > descMeshConnB(nbOfCells);
686 std::vector< std::vector<int> > revDescMeshConnB;
687 std::vector< std::vector<int> > revNodalB(nbOfNodes);
688 std::vector<int> meshDM1Conn;
689 std::vector<int> meshDM1ConnIndex(1); meshDM1ConnIndex[0]=0;
690 std::vector<int> meshDM1Type;
691 for(int eltId=0;eltId<nbOfCells;eltId++)
693 int pos=connIndex[eltId];
694 int posP1=connIndex[eltId+1];
695 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[pos]);
696 unsigned nbOfSons=cm.getNumberOfSons2(conn+pos+1,posP1-pos-1);
697 int *tmp=new int[posP1-pos];
698 for(unsigned i=0;i<nbOfSons;i++)
700 INTERP_KERNEL::NormalizedCellType cmsId;
701 unsigned nbOfNodesSon=cm.fillSonCellNodalConnectivity2(i,conn+pos+1,posP1-pos-1,tmp,cmsId);
702 const INTERP_KERNEL::CellModel& cms=INTERP_KERNEL::CellModel::GetCellModel(cmsId);
703 std::set<int> shareableCells(revNodalB[tmp[0]].begin(),revNodalB[tmp[0]].end());
704 for(unsigned j=1;j<nbOfNodesSon && !shareableCells.empty();j++)
706 std::set<int> tmp2(revNodalB[tmp[j]].begin(),revNodalB[tmp[j]].end());
708 std::set_intersection(tmp2.begin(),tmp2.end(),shareableCells.begin(),shareableCells.end(),inserter(tmp3,tmp3.begin()));
711 std::list<int> shareableCellsL(shareableCells.begin(),shareableCells.end());
712 std::set<int> ref(tmp,tmp+nbOfNodesSon);
713 for(std::list<int>::iterator iter=shareableCellsL.begin();iter!=shareableCellsL.end();)
715 if(cms.isCompatibleWith((INTERP_KERNEL::NormalizedCellType)meshDM1Type[*iter]))
717 std::set<int> ref2(meshDM1Conn.begin()+meshDM1ConnIndex[*iter],meshDM1Conn.begin()+meshDM1ConnIndex[(*iter)+1]);
721 iter=shareableCellsL.erase(iter);
724 iter=shareableCellsL.erase(iter);
726 if(shareableCellsL.empty())
728 meshDM1Conn.insert(meshDM1Conn.end(),tmp,tmp+nbOfNodesSon);
729 meshDM1ConnIndex.push_back(meshDM1ConnIndex.back()+nbOfNodesSon);
730 int cellDM1Id=(int)meshDM1Type.size();
731 meshDM1Type.push_back((int)cmsId);
732 for(unsigned k=0;k<nbOfNodesSon;k++)
733 revNodalB[tmp[k]].push_back(cellDM1Id);
734 revDescMeshConnB.resize(cellDM1Id+1);
735 revDescMeshConnB.back().push_back(eltId);
736 descMeshConnB[eltId].push_back(nbrer(cellDM1Id,0,cms,false,0,0));
740 int DM1cellId=shareableCellsL.front();
741 revDescMeshConnB[DM1cellId].push_back(eltId);
742 descMeshConnB[eltId].push_back(nbrer(DM1cellId,nbOfNodesSon,cms,true,tmp,&meshDM1Conn[meshDM1ConnIndex[DM1cellId]]));
749 std::string name="Mesh constituent of "; name+=getName();
750 MEDCouplingUMesh *ret=MEDCouplingUMesh::New(name.c_str(),getMeshDimension()-1);
751 ret->setCoords(getCoords());
752 int nbOfCellsInConstituent=(int)meshDM1Type.size();
753 ret->allocateCells(nbOfCellsInConstituent);
754 revDescIndx->alloc(nbOfCellsInConstituent+1,1);
755 int *tmp3=revDescIndx->getPointer(); tmp3[0]=0;
756 for(int ii=0;ii<nbOfCellsInConstituent;ii++)
758 ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)meshDM1Type[ii],meshDM1ConnIndex[ii+1]-meshDM1ConnIndex[ii],&meshDM1Conn[meshDM1ConnIndex[ii]]);
759 tmp3[ii+1]=tmp3[ii]+((int)revDescMeshConnB[ii].size());
761 ret->finishInsertingCells();
762 revDesc->alloc(tmp3[nbOfCellsInConstituent],1);
763 tmp3=revDesc->getPointer();
764 for(std::vector< std::vector<int> >::const_iterator iter2=revDescMeshConnB.begin();iter2!=revDescMeshConnB.end();iter2++)
765 tmp3=std::copy((*iter2).begin(),(*iter2).end(),tmp3);
766 meshDM1Type.clear(); meshDM1ConnIndex.clear(); meshDM1Conn.clear();
767 descIndx->alloc(nbOfCells+1,1);
768 tmp3=descIndx->getPointer(); tmp3[0]=0;
769 for(int jj=0;jj<nbOfCells;jj++)
770 tmp3[jj+1]=tmp3[jj]+((int)descMeshConnB[jj].size());
771 desc->alloc(tmp3[nbOfCells],1);
772 tmp3=desc->getPointer();
773 for(std::vector< std::vector<int> >::const_iterator iter3=descMeshConnB.begin();iter3!=descMeshConnB.end();iter3++)
774 tmp3=std::copy((*iter3).begin(),(*iter3).end(),tmp3);
779 struct MEDCouplingAccVisit
781 MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
782 int operator()(int val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
783 int _new_nb_of_nodes;
790 * This method convert cell with ids in ['cellIdsToConvertBg','cellIdsToConvertEnd') into 'this' into dynamic types without changing geometry.
791 * That is to say if 'this' is a 2D, mesh after the invocation of this method it will contain only polygons.
792 * If 'this' is a 3D mesh after the invocation of this method it will contain only polyhedra.
793 * If mesh dimension is not in [2,3] an exception is thrown.
794 * Of course pay attention that the resulting mesh is slower than previous one.
795 * If in ['cellIdsToConvertBg','cellIdsToConvertEnd') there is a cell id not in [0,'this->getNumberOfCells()') an exception will be thrown.
796 * In this case if meshDim==2 the mesh is still valid and only cells treated before throw will be converted into polygon.
797 * If mesh==3, after throw the mesh is \b unconsistent !
798 * This method is above all designed to test more extensively algorithms able to deal with polygons/polyhedra.
800 * \warning This method modifies can modify significantly the geometric type order in \a this.
801 * In view of the MED file writing, a renumbering of cells in \a this (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
803 void MEDCouplingUMesh::convertToPolyTypes(const int *cellIdsToConvertBg, const int *cellIdsToConvertEnd)
806 int dim=getMeshDimension();
808 throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
809 int nbOfCells=getNumberOfCells();
812 const int *connIndex=_nodal_connec_index->getConstPointer();
813 int *conn=_nodal_connec->getPointer();
814 for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
816 if(*iter>=0 && *iter<nbOfCells)
818 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
820 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
822 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
826 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
827 oss << " in range [0," << nbOfCells << ") !";
828 throw INTERP_KERNEL::Exception(oss.str().c_str());
834 int *connIndex=_nodal_connec_index->getPointer();
835 int connIndexLgth=_nodal_connec_index->getNbOfElems();
836 const int *connOld=_nodal_connec->getConstPointer();
837 int connOldLgth=_nodal_connec->getNbOfElems();
838 std::vector<int> connNew(connOld,connOld+connOldLgth);
839 for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
841 if(*iter>=0 && *iter<nbOfCells)
843 int pos=connIndex[*iter];
844 int posP1=connIndex[(*iter)+1];
845 int lgthOld=posP1-pos-1;
846 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connNew[pos]);
847 connNew[pos]=INTERP_KERNEL::NORM_POLYHED;
848 unsigned nbOfFaces=cm.getNumberOfSons2(&connNew[pos+1],lgthOld);
849 int *tmp=new int[nbOfFaces*lgthOld];
851 for(int j=0;j<(int)nbOfFaces;j++)
853 INTERP_KERNEL::NormalizedCellType type;
854 unsigned offset=cm.fillSonCellNodalConnectivity2(j,&connNew[pos+1],lgthOld,work,type);
858 std::size_t newLgth=std::distance(tmp,work)-1;
859 std::size_t delta=newLgth-lgthOld;
860 std::transform(connIndex+(*iter)+1,connIndex+connIndexLgth,connIndex+(*iter)+1,std::bind2nd(std::plus<int>(),delta));
861 connNew.insert(connNew.begin()+posP1,tmp+lgthOld,tmp+newLgth);
862 std::copy(tmp,tmp+lgthOld,connNew.begin()+pos+1);
867 std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
868 oss << " in range [0," << nbOfCells << ") !";
869 throw INTERP_KERNEL::Exception(oss.str().c_str());
872 _nodal_connec->alloc((int)connNew.size(),1);
873 int *newConnPtr=_nodal_connec->getPointer();
874 std::copy(connNew.begin(),connNew.end(),newConnPtr);
880 * This method converts all cells into poly type if possible.
881 * This method is purely for userfriendliness.
882 * As this method can be costly in Memory, no optimization is done to avoid construction of useless vector.
884 void MEDCouplingUMesh::convertAllToPoly()
886 int nbOfCells=getNumberOfCells();
887 std::vector<int> cellIds(nbOfCells);
888 for(int i=0;i<nbOfCells;i++)
890 convertToPolyTypes(&cellIds[0],&cellIds[0]+cellIds.size());
894 * This method expects that 'this' has a spacedim equal to 3 and a mesh dimension equal to 3 too, if not an exception will be thrown.
895 * This method work only on cells with type NORM_POLYHED, all other cells with different type, are remains unchanged.
896 * For such polyhedra, they are expected to have only 1 face (containing 2 faces in opposition), having 2*n number of nodes (n nodes on
897 * each 2 faces hidden in the single face of polyhedron).
898 * The first face is expected to be right oriented because all faces of this polyhedron will be deduced.
899 * When called 'this' is an invalid mesh on MED sense. This method will correct that for polyhedra.
900 * In case of presence of polyhedron that has not the extruded aspect (2 faces with the same number of nodes) an exception is thrown and 'this'
902 * This method is usefull only for users that wants to build extruded unstructured mesh.
903 * This method is a convenient one that avoids boring polyhedra setting during insertNextCell process.
904 * In case of success, 'this' has be corrected contains the same number of cells and is valid in MED sense.
906 void MEDCouplingUMesh::convertExtrudedPolyhedra() throw(INTERP_KERNEL::Exception)
909 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
910 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
911 int nbOfCells=getNumberOfCells();
912 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newCi=DataArrayInt::New();
913 newCi->alloc(nbOfCells+1,1);
914 int *newci=newCi->getPointer();
915 const int *ci=_nodal_connec_index->getConstPointer();
916 const int *c=_nodal_connec->getConstPointer();
918 for(int i=0;i<nbOfCells;i++)
920 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
921 if(type==INTERP_KERNEL::NORM_POLYHED)
923 if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
925 std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
926 throw INTERP_KERNEL::Exception(oss.str().c_str());
928 std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
931 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 !";
932 throw INTERP_KERNEL::Exception(oss.str().c_str());
935 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)
938 newci[i+1]=(ci[i+1]-ci[i])+newci[i];
940 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newC=DataArrayInt::New();
941 newC->alloc(newci[nbOfCells],1);
942 int *newc=newC->getPointer();
943 for(int i=0;i<nbOfCells;i++)
945 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
946 if(type==INTERP_KERNEL::NORM_POLYHED)
948 std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
949 newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
951 for(std::size_t j=0;j<n1;j++)
953 newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
955 newc[n1+5*j+1]=c[ci[i]+1+j];
956 newc[n1+5*j+2]=c[ci[i]+1+(j+1)%n1];
957 newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
958 newc[n1+5*j+4]=c[ci[i]+1+j+n1];
963 newc=std::copy(c+ci[i],c+ci[i+1],newc);
965 _nodal_connec_index->decrRef(); _nodal_connec_index=newCi;
966 _nodal_connec->decrRef(); _nodal_connec=newC;
967 newC->incrRef(); newCi->incrRef();
971 * This method is the opposite of ParaMEDMEM::MEDCouplingUMesh::convertToPolyTypes method.
972 * The aim is to take all polygons or polyhedrons cell and to try to traduce them into classical cells.
974 * \return If true at least one cell has been unpolyzed.
975 \n If false has been returned the nodal connectivity of \a this has **not** been altered and \a this has remains unchanged.
977 * \warning This method modifies can modify significantly the geometric type order in \a this.
978 * In view of the MED file writing, a renumbering of cells in \a this (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
980 bool MEDCouplingUMesh::unPolyze()
983 int mdim=getMeshDimension();
985 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
988 int nbOfCells=getNumberOfCells();
991 int initMeshLgth=getMeshLength();
992 int *conn=_nodal_connec->getPointer();
993 int *index=_nodal_connec_index->getPointer();
998 for(int i=0;i<nbOfCells;i++)
1000 lgthOfCurCell=index[i+1]-posOfCurCell;
1001 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1002 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1003 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1007 switch(cm.getDimension())
1011 INTERP_KERNEL::AutoPtr<int> tmp=new int[lgthOfCurCell-1];
1012 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(int *)tmp);
1013 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1018 int nbOfFaces,lgthOfPolyhConn;
1019 INTERP_KERNEL::AutoPtr<int> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1020 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1025 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1029 ret=ret || (newType!=type);
1030 conn[newPos]=newType;
1032 posOfCurCell=index[i+1];
1037 std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1038 newPos+=lgthOfCurCell;
1039 posOfCurCell+=lgthOfCurCell;
1043 if(newPos!=initMeshLgth)
1044 _nodal_connec->reAlloc(newPos);
1051 * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1052 * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1053 * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells.
1055 * \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
1058 void MEDCouplingUMesh::simplifyPolyhedra(double eps) throw(INTERP_KERNEL::Exception)
1060 checkFullyDefined();
1061 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1062 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1063 MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> coords=getCoords()->deepCpy();
1064 coords->recenterForMaxPrecision(eps);
1066 int nbOfCells=getNumberOfCells();
1067 const int *conn=_nodal_connec->getConstPointer();
1068 const int *index=_nodal_connec_index->getConstPointer();
1069 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> connINew=DataArrayInt::New();
1070 connINew->alloc(nbOfCells+1,1);
1071 int *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1072 std::vector<int> connNew;
1074 for(int i=0;i<nbOfCells;i++,connINewPtr++)
1076 if(conn[index[i]]==(int)INTERP_KERNEL::NORM_POLYHED)
1078 SimplifyPolyhedronCell(eps,coords,conn+index[i],conn+index[i+1],connNew);
1082 connNew.insert(connNew.end(),conn+index[i],conn+index[i+1]);
1083 *connINewPtr=(int)connNew.size();
1087 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> connNew2=DataArrayInt::New();
1088 connNew2->alloc((int)connNew.size(),1);
1089 std::copy(connNew.begin(),connNew.end(),connNew2->getPointer());
1090 setConnectivity(connNew2,connINew,false);
1095 * This method returns all node ids used in \b this. The data array returned has to be dealt by the caller.
1096 * The returned node ids are sortes ascendingly. This method is closed to MEDCouplingUMesh::getNodeIdsInUse except
1097 * the format of returned DataArrayInt instance.
1099 * @return a newly allocated DataArrayInt sorted ascendingly of fetched node ids.
1100 * \sa MEDCouplingUMesh::getNodeIdsInUse
1102 DataArrayInt *MEDCouplingUMesh::computeFetchedNodeIds() const throw(INTERP_KERNEL::Exception)
1104 checkConnectivityFullyDefined();
1106 int nbOfCells=getNumberOfCells();
1107 const int *connIndex=_nodal_connec_index->getConstPointer();
1108 const int *conn=_nodal_connec->getConstPointer();
1109 for(int i=0;i<nbOfCells;i++)
1110 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1112 retS.insert(conn[j]);
1113 DataArrayInt *ret=DataArrayInt::New();
1114 ret->alloc((int)retS.size(),1);
1115 std::copy(retS.begin(),retS.end(),ret->getPointer());
1120 * Array returned is the correspondance in \b old \b to \b new format (that's why 'nbrOfNodesInUse' is returned too).
1121 * The returned array is newly created and should be dealt by the caller.
1122 * To retrieve the new to old format the user can use DataArrayInt::invertArrayO2N2N2O method.
1123 * The size of returned array is the number of nodes of 'this'.
1124 * -1 values in returned array means that the corresponding node never appear in any nodal connectivity of cells constituting 'this'.
1125 * @param [out] nbrOfNodesInUse out parameter that specifies how many of nodes in 'this' is really used in nodal connectivity.
1126 * @return a newly allocated DataArrayInt that tells for each nodeid in \b this if it is unused (-1) or used (the corresponding new id)
1128 DataArrayInt *MEDCouplingUMesh::getNodeIdsInUse(int& nbrOfNodesInUse) const throw(INTERP_KERNEL::Exception)
1131 int nbOfNodes=getNumberOfNodes();
1132 DataArrayInt *ret=DataArrayInt::New();
1133 ret->alloc(nbOfNodes,1);
1134 int *traducer=ret->getPointer();
1135 std::fill(traducer,traducer+nbOfNodes,-1);
1136 int nbOfCells=getNumberOfCells();
1137 const int *connIndex=_nodal_connec_index->getConstPointer();
1138 const int *conn=_nodal_connec->getConstPointer();
1139 for(int i=0;i<nbOfCells;i++)
1140 for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1142 traducer[conn[j]]=1;
1143 nbrOfNodesInUse=(int)std::count(traducer,traducer+nbOfNodes,1);
1144 std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1149 * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1150 * For each cell in \b this the number of nodes constituting cell is computed.
1151 * Excepted for poyhedrons, the result can be deduced by performing a deltaShiftIndex on the nodal connectivity index in \b this minus 1.
1152 * For polyhedrons, the face separation (-1) are excluded from the couting.
1154 * \return a newly allocated array
1156 DataArrayInt *MEDCouplingUMesh::computeNbOfNodesPerCell() const throw(INTERP_KERNEL::Exception)
1158 checkConnectivityFullyDefined();
1159 int nbOfCells=getNumberOfCells();
1160 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret=DataArrayInt::New();
1161 ret->alloc(nbOfCells,1);
1162 int *retPtr=ret->getPointer();
1163 const int *conn=getNodalConnectivity()->getConstPointer();
1164 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1165 for(int i=0;i<nbOfCells;i++,retPtr++)
1167 if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1168 *retPtr=connI[i+1]-connI[i]-1;
1170 *retPtr=connI[i+1]-connI[i]-1-std::count(conn+connI[i]+1,conn+connI[i+1],-1);
1172 ret->incrRef(); return ret;
1176 * Array returned is the correspondance in \b old \b to \b new format. The returned array is newly created and should be dealt by the caller.
1177 * The maximum value stored in returned array is the number of nodes of 'this' minus 1 after call of this method.
1178 * The size of returned array is the number of nodes of the old (previous to the call of this method) number of nodes.
1179 * -1 values in returned array means that the corresponding old node is no more used.
1181 DataArrayInt *MEDCouplingUMesh::zipCoordsTraducer() throw(INTERP_KERNEL::Exception)
1183 int newNbOfNodes=-1;
1184 DataArrayInt *traducer=getNodeIdsInUse(newNbOfNodes);
1185 renumberNodes(traducer->getConstPointer(),newNbOfNodes);
1190 * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1191 * The semantic of 'compType' is specified in MEDCouplingUMesh::zipConnectivityTraducer method.
1193 int MEDCouplingUMesh::areCellsEqual(int cell1, int cell2, int compType) const
1198 return areCellsEqual0(cell1,cell2);
1200 return areCellsEqual1(cell1,cell2);
1202 return areCellsEqual2(cell1,cell2);
1204 return areCellsEqual7(cell1,cell2);
1206 throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1 or 2.");
1210 * This method is the last step of the MEDCouplingUMesh::zipConnectivityTraducer with policy 0.
1212 int MEDCouplingUMesh::areCellsEqual0(int cell1, int cell2) const
1214 const int *conn=getNodalConnectivity()->getConstPointer();
1215 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1216 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1217 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1222 * This method is the last step of the MEDCouplingUMesh::zipConnectivityTraducer with policy 1.
1224 int MEDCouplingUMesh::areCellsEqual1(int cell1, int cell2) const
1226 const int *conn=getNodalConnectivity()->getConstPointer();
1227 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1228 int sz=connI[cell1+1]-connI[cell1];
1229 if(sz==connI[cell2+1]-connI[cell2])
1231 if(conn[connI[cell1]]==conn[connI[cell2]])
1233 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1234 unsigned dim=cm.getDimension();
1240 int *tmp=new int[sz1];
1241 int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],tmp);
1242 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1243 work=std::search(tmp,tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1245 return work!=tmp+sz1?1:0;
1248 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1251 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areCellsEqual1 : not implemented yet for meshdim == 3 !");
1258 * This method is the last step of the MEDCouplingUMesh::zipConnectivityTraducer with policy 2.
1260 int MEDCouplingUMesh::areCellsEqual2(int cell1, int cell2) const
1262 const int *conn=getNodalConnectivity()->getConstPointer();
1263 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1264 if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1266 if(conn[connI[cell1]]==conn[connI[cell2]])
1268 std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1269 std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1277 * This method is the last step of the MEDCouplingUMesh::zipConnectivityTraducer with policy 7.
1279 int MEDCouplingUMesh::areCellsEqual7(int cell1, int cell2) const
1281 const int *conn=getNodalConnectivity()->getConstPointer();
1282 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1283 int sz=connI[cell1+1]-connI[cell1];
1284 if(sz==connI[cell2+1]-connI[cell2])
1286 if(conn[connI[cell1]]==conn[connI[cell2]])
1288 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1289 unsigned dim=cm.getDimension();
1295 int *tmp=new int[sz1];
1296 int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],tmp);
1297 std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1298 work=std::search(tmp,tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1306 std::reverse_iterator<int *> it1(tmp+sz1);
1307 std::reverse_iterator<int *> it2(tmp);
1308 if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1320 return work!=tmp+sz1?1:0;
1323 {//case of SEG2 and SEG3
1324 if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1326 if(!cm.isQuadratic())
1328 std::reverse_iterator<const int *> it1(conn+connI[cell1+1]);
1329 std::reverse_iterator<const int *> it2(conn+connI[cell1]+1);
1330 if(std::equal(it1,it2,conn+connI[cell2]+1))
1336 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])
1343 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areCellsEqual7 : not implemented yet for meshdim == 3 !");
1351 * This method compares 2 cells coming from two unstructured meshes : 'this' and 'other'.
1352 * This method compares 2 cells having the same id 'cellId' in 'this' and 'other'.
1354 bool MEDCouplingUMesh::areCellsFrom2MeshEqual(const MEDCouplingUMesh *other, int cellId, double prec) const
1356 if(getTypeOfCell(cellId)!=other->getTypeOfCell(cellId))
1358 std::vector<int> c1,c2;
1359 getNodeIdsOfCell(cellId,c1);
1360 other->getNodeIdsOfCell(cellId,c2);
1361 std::size_t sz=c1.size();
1364 for(std::size_t i=0;i<sz;i++)
1366 std::vector<double> n1,n2;
1367 getCoordinatesOfNode(c1[0],n1);
1368 other->getCoordinatesOfNode(c2[0],n2);
1369 std::transform(n1.begin(),n1.end(),n2.begin(),n1.begin(),std::minus<double>());
1370 std::transform(n1.begin(),n1.end(),n1.begin(),std::ptr_fun<double,double>(fabs));
1371 if(*std::max_element(n1.begin(),n1.end())>prec)
1378 * This method find in candidate pool defined by 'candidates' the cells equal following the polycy 'compType'.
1379 * If any true is returned and the results will be put at the end of 'result' output parameter. If not false is returned
1380 * and result remains unchanged.
1381 * The semantic of 'compType' is specified in MEDCouplingUMesh::zipConnectivityTraducer method.
1382 * If in 'candidates' pool -1 value is considered as an empty value.
1383 * WARNING this method returns only ONE set of result !
1385 bool MEDCouplingUMesh::areCellsEqualInPool(const std::vector<int>& candidates, int compType, std::vector<int>& result) const
1387 std::set<int> cand(candidates.begin(),candidates.end());
1392 std::set<int>::const_iterator iter=cand.begin();
1393 int start=(*iter++);
1394 for(;iter!=cand.end();iter++)
1396 int status=areCellsEqual(start,*iter,compType);
1401 result.push_back(start);
1405 result.push_back(*iter);
1407 result.push_back(status==2?(*iter+1):-(*iter+1));
1414 * This method common cells base regarding 'compType' comparison policy described in ParaMEDMEM::MEDCouplingUMesh::zipConnectivityTraducer for details.
1415 * This method returns 2 values 'res' and 'resI'.
1416 * If 'res' and 'resI' are not empty before calling this method they will be cleared before set.
1417 * The format of 'res' and 'resI' is as explained here.
1418 * resI.size()-1 is the number of set of cells equal.
1419 * The nth set is [res.begin()+resI[n];res.begin()+resI[n+1]) with 0<=n<resI.size()-1
1421 template<int SPACEDIM>
1422 void MEDCouplingUMesh::findCommonCellsBase(int compType, std::vector<int>& res, std::vector<int>& resI) const
1424 res.clear(); resI.clear();
1426 std::vector<double> bbox;
1427 int nbOfCells=getNumberOfCells();
1428 getBoundingBoxForBBTree(bbox);
1429 double bb[2*SPACEDIM];
1430 double eps=getCaracteristicDimension();
1432 BBTree<SPACEDIM,int> myTree(&bbox[0],0,0,nbOfCells,-eps);
1433 const int *conn=getNodalConnectivity()->getConstPointer();
1434 const int *connI=getNodalConnectivityIndex()->getConstPointer();
1435 const double *coords=getCoords()->getConstPointer();
1436 std::vector<bool> isFetched(nbOfCells);
1437 for(int k=0;k<nbOfCells;k++)
1441 for(int j=0;j<SPACEDIM;j++)
1442 { bb[2*j]=std::numeric_limits<double>::max(); bb[2*j+1]=-std::numeric_limits<double>::max(); }
1443 for(const int *pt=conn+connI[k]+1;pt!=conn+connI[k+1];pt++)
1446 for(int j=0;j<SPACEDIM;j++)
1448 bb[2*j]=std::min(bb[2*j],coords[SPACEDIM*(*pt)+j]);
1449 bb[2*j+1]=std::max(bb[2*j+1],coords[SPACEDIM*(*pt)+j]);
1452 std::vector<int> candidates1;
1453 myTree.getIntersectingElems(bb,candidates1);
1454 std::vector<int> candidates;
1455 for(std::vector<int>::const_iterator iter=candidates1.begin();iter!=candidates1.end();iter++)
1456 if(!isFetched[*iter])
1457 candidates.push_back(*iter);
1458 if(areCellsEqualInPool(candidates,compType,res))
1460 int pos=resI.back();
1461 resI.push_back((int)res.size());
1462 for(std::vector<int>::const_iterator it=res.begin()+pos;it!=res.end();it++)
1463 isFetched[*it]=true;
1471 * This method could potentially modify 'this'. This method merges cells if there are cells equal in 'this'. The comparison is specified by 'compType'.
1472 * This method keeps the coordiantes of 'this'.
1474 * @param compType input specifying the technique used to compare cells each other.
1475 * - 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.
1476 * - 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)
1477 * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1478 * - 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
1479 * can be used for users not sensitive to orientation of cell
1480 * @return the correspondance array old to new.
1482 * \warning This method modifies can modify significantly the geometric type order in \a this.
1483 * In view of the MED file writing, a renumbering of cells in \a this (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
1485 DataArrayInt *MEDCouplingUMesh::zipConnectivityTraducer(int compType) throw(INTERP_KERNEL::Exception)
1487 int spaceDim=getSpaceDimension();
1488 int nbOfCells=getNumberOfCells();
1489 std::vector<int> commonCells;
1490 std::vector<int> commonCellsI;
1495 findCommonCellsBase<3>(compType,commonCells,commonCellsI);
1500 findCommonCellsBase<2>(compType,commonCells,commonCellsI);
1505 findCommonCellsBase<1>(compType,commonCells,commonCellsI);
1509 throw INTERP_KERNEL::Exception("Invalid spaceDimension : must be 1, 2 or 3.");
1511 DataArrayInt *ret=DataArrayInt::New();
1512 ret->alloc(nbOfCells,1);
1513 int *retPtr=ret->getPointer();
1514 std::fill(retPtr,retPtr+nbOfCells,0);
1515 const std::size_t nbOfTupleSmCells=commonCellsI.size()-1;
1517 std::vector<int> cellsToKeep;
1518 for(std::size_t i=0;i<nbOfTupleSmCells;i++)
1520 for(std::vector<int>::const_iterator it=commonCells.begin()+commonCellsI[i];it!=commonCells.begin()+commonCellsI[i+1];it++)
1525 std::map<int,int> m;
1526 for(int i=0;i<nbOfCells;i++)
1532 cellsToKeep.push_back(i);
1536 std::map<int,int>::const_iterator iter=m.find(val);
1541 cellsToKeep.push_back(i);
1544 retPtr[i]=(*iter).second;
1547 MEDCouplingUMesh *self=(MEDCouplingUMesh *)buildPartOfMySelf(&cellsToKeep[0],&cellsToKeep[0]+cellsToKeep.size(),true);
1548 setConnectivity(self->getNodalConnectivity(),self->getNodalConnectivityIndex(),true);
1554 * This method makes the assumption that 'this' and 'other' share the same coords. If not an exception will be thrown !
1555 * This method tries to determine if 'other' is fully included in 'this'. To compute that, this method works with connectivity as MEDCouplingUMesh::zipConnectivityTraducer method does.
1556 * This method is close to MEDCouplingUMesh::checkDeepEquivalOnSameNodesWith or MEDCouplingMesh::checkGeoEquivalWith with policy 20,21,or 22.
1557 * The main difference is that this method is not expected to throw exception.
1558 * This method has two outputs :
1560 * @param compType is the comparison type. The possible values of this parameter are described in ParaMEDMEM::MEDCouplingUMesh::zipConnectivityTraducer method
1561 * @param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1562 * @return If 'other' is fully included in 'this 'true is returned. If not false is returned.
1564 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayInt *& arr) const throw(INTERP_KERNEL::Exception)
1566 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1567 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> o2n=mesh->zipConnectivityTraducer(compType);
1568 int nbOfCells=getNumberOfCells();
1569 arr=o2n->substr(nbOfCells);
1570 arr->setName(other->getName());
1572 if(other->getNumberOfCells()==0)
1574 return arr->getMaxValue(tmp)<nbOfCells;
1578 * This method makes the assumption that 'this' and 'other' share the same coords. If not an exception will be thrown !
1579 * This method tries to determine if \b other is fully included in \b this.
1580 * The main difference is that this method is not expected to throw exception.
1581 * This method has two outputs :
1583 * @param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1584 * @return If 'other' is fully included in 'this 'true is returned. If not false is returned.
1586 bool MEDCouplingUMesh::areCellsIncludedIn2(const MEDCouplingUMesh *other, DataArrayInt *& arr) const throw(INTERP_KERNEL::Exception)
1588 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1589 int spaceDim=mesh->getSpaceDimension();
1590 std::vector<int> commonCells;
1591 std::vector<int> commonCellsI;
1596 findCommonCellsBase<3>(7,commonCells,commonCellsI);
1601 findCommonCellsBase<2>(7,commonCells,commonCellsI);
1606 findCommonCellsBase<1>(7,commonCells,commonCellsI);
1610 throw INTERP_KERNEL::Exception("Invalid spaceDimension : must be 1, 2 or 3.");
1612 int thisNbCells=getNumberOfCells();
1613 int otherNbCells=other->getNumberOfCells();
1614 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> arr2=DataArrayInt::New();
1615 arr2->alloc(otherNbCells,1);
1616 arr2->fillWithZero();
1617 int *arr2Ptr=arr2->getPointer();
1618 int nbOfCommon=(int)commonCellsI.size()-1;
1619 for(int i=0;i<nbOfCommon;i++)
1621 int start=commonCells[commonCellsI[i]];
1622 if(start<thisNbCells)
1624 for(int j=commonCellsI[i]+1;j!=commonCellsI[i+1];j++)
1626 int sig=commonCells[j]>0?1:-1;
1627 int val=std::abs(commonCells[j])-1;
1628 if(val>=thisNbCells)
1629 arr2Ptr[val-thisNbCells]=sig*(start+1);
1633 arr2->setName(other->getName());
1634 if(arr2->presenceOfValue(0))
1642 * @param areNodesMerged if at least two nodes have been merged.
1643 * @return old to new node correspondance.
1645 DataArrayInt *MEDCouplingUMesh::mergeNodes(double precision, bool& areNodesMerged, int& newNbOfNodes)
1647 DataArrayInt *ret=buildPermArrayForMergeNode(precision,-1,areNodesMerged,newNbOfNodes);
1649 renumberNodes(ret->getConstPointer(),newNbOfNodes);
1654 * Idem ParaMEDMEM::MEDCouplingUMesh::mergeNodes method except that the merged nodes are meld into the barycenter of them.
1656 DataArrayInt *MEDCouplingUMesh::mergeNodes2(double precision, bool& areNodesMerged, int& newNbOfNodes)
1658 DataArrayInt *ret=buildPermArrayForMergeNode(precision,-1,areNodesMerged,newNbOfNodes);
1660 renumberNodes2(ret->getConstPointer(),newNbOfNodes);
1665 * This method tries to use 'other' coords and use it for 'this'. If no exception was thrown after the call of this method :
1666 * this->_coords==other->_coords. If an exception is thrown 'this' remains unchanged.
1667 * Contrary to MEDCouplingUMesh::tryToShareSameCoords method this method makes a deeper analyze of coordinates (and so more expensive) than simple equality.
1668 * Two nodes one in 'this' and other in 'other' are considered equal if the distance between the two is lower than epsilon.
1670 void MEDCouplingUMesh::tryToShareSameCoordsPermute(const MEDCouplingPointSet& other, double epsilon) throw(INTERP_KERNEL::Exception)
1672 const DataArrayDouble *coords=other.getCoords();
1674 throw INTERP_KERNEL::Exception("tryToShareSameCoordsPermute : No coords specified in other !");
1676 throw INTERP_KERNEL::Exception("tryToShareSameCoordsPermute : No coords specified in this whereas there is any in other !");
1677 int otherNbOfNodes=other.getNumberOfNodes();
1678 MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> newCoords=MergeNodesArray(&other,this);
1680 MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> oldCoords=_coords;
1681 setCoords(newCoords);
1682 bool areNodesMerged;
1684 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> da=buildPermArrayForMergeNode(epsilon,otherNbOfNodes,areNodesMerged,newNbOfNodes);
1687 setCoords(oldCoords);
1688 throw INTERP_KERNEL::Exception("tryToShareSameCoordsPermute fails : no nodes are mergeable with specified given epsilon !");
1690 int maxId=*std::max_element(da->getConstPointer(),da->getConstPointer()+otherNbOfNodes);
1691 const int *pt=std::find_if(da->getConstPointer()+otherNbOfNodes,da->getConstPointer()+da->getNbOfElems(),std::bind2nd(std::greater<int>(),maxId));
1692 if(pt!=da->getConstPointer()+da->getNbOfElems())
1694 setCoords(oldCoords);
1695 throw INTERP_KERNEL::Exception("tryToShareSameCoordsPermute fails : some nodes in this are not in other !");
1697 setCoords(oldCoords);
1698 renumberNodesInConn(da->getConstPointer()+otherNbOfNodes);
1703 * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
1704 * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
1705 * cellIds is not given explicitely but by a range python like.
1707 * \param keepCoords that specifies if you want or not to keep coords as this or zip it (see ParaMEDMEM::MEDCouplingUMesh::zipCoords). If true zipCoords is \b NOT called, if false, zipCoords is called.
1708 * \return a newly allocated
1710 * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
1711 * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
1713 MEDCouplingPointSet *MEDCouplingUMesh::buildPartOfMySelf2(int start, int end, int step, bool keepCoords) const throw(INTERP_KERNEL::Exception)
1715 if(getMeshDimension()!=-1)
1717 MEDCouplingUMesh *ret=buildPartOfMySelfKeepCoords2(start,end,step);
1724 int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelf2 for -1 dimension mesh ");
1726 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1728 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1730 return const_cast<MEDCouplingUMesh *>(this);
1735 * build a sub part of \b this. This sub part is defined by the cell ids contained in the array in [begin,end).
1736 * @param begin begin of array containing the cell ids to keep.
1737 * @param end end of array of cell ids to keep. \b WARNING end param is \b not included ! Idem STL standard definitions.
1738 * @param keepCoords that specifies if you want or not to keep coords as this or zip it (see ParaMEDMEM::MEDCouplingUMesh::zipCoords). If true zipCoords is \b NOT called, if false, zipCoords is called.
1740 * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
1741 * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
1743 MEDCouplingPointSet *MEDCouplingUMesh::buildPartOfMySelf(const int *begin, const int *end, bool keepCoords) const
1745 if(getMeshDimension()!=-1)
1747 MEDCouplingUMesh *ret=buildPartOfMySelfKeepCoords(begin,end);
1755 throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1757 throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1759 return const_cast<MEDCouplingUMesh *>(this);
1764 * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
1766 * 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.
1767 * Size of [\b cellIdsBg, \b cellIdsEnd) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
1768 * The number of cells of \b this will remain the same with this method.
1770 * \param [in] begin begin of cell ids (included) of cells in this to assign
1771 * \param [in] end end of cell ids (excluded) of cells in this to assign
1772 * \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).
1773 * Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
1775 void MEDCouplingUMesh::setPartOfMySelf(const int *cellIdsBg, const int *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis) throw(INTERP_KERNEL::Exception)
1777 checkConnectivityFullyDefined();
1778 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
1779 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
1780 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
1781 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
1783 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
1784 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
1785 throw INTERP_KERNEL::Exception(oss.str().c_str());
1787 int nbOfCellsToModify=(int)std::distance(cellIdsBg,cellIdsEnd);
1788 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
1790 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
1791 throw INTERP_KERNEL::Exception(oss.str().c_str());
1793 int nbOfCells=getNumberOfCells();
1794 bool easyAssign=true;
1795 const int *connI=_nodal_connec_index->getConstPointer();
1796 const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
1797 for(const int *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
1799 if(*it>=0 && *it<nbOfCells)
1801 easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
1805 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
1806 throw INTERP_KERNEL::Exception(oss.str().c_str());
1811 MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
1816 DataArrayInt *arrOut=0,*arrIOut=0;
1817 MEDCouplingUMesh::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
1819 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
1820 setConnectivity(arrOut,arrIOut,true);
1824 void MEDCouplingUMesh::setPartOfMySelf2(int start, int end, int step, const MEDCouplingUMesh& otherOnSameCoordsThanThis) throw(INTERP_KERNEL::Exception)
1826 checkConnectivityFullyDefined();
1827 otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
1828 if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
1829 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf2 : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
1830 if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
1832 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf2 : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
1833 oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
1834 throw INTERP_KERNEL::Exception(oss.str().c_str());
1836 int nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelf2 : ");
1837 if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
1839 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf2 : cells ids length (" << nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
1840 throw INTERP_KERNEL::Exception(oss.str().c_str());
1842 int nbOfCells=getNumberOfCells();
1843 bool easyAssign=true;
1844 const int *connI=_nodal_connec_index->getConstPointer();
1845 const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
1847 for(int i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
1849 if(it>=0 && it<nbOfCells)
1851 easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
1855 std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf2 : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
1856 throw INTERP_KERNEL::Exception(oss.str().c_str());
1861 MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx2(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
1866 DataArrayInt *arrOut=0,*arrIOut=0;
1867 MEDCouplingUMesh::SetPartOfIndexedArrays2(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
1869 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
1870 setConnectivity(arrOut,arrIOut,true);
1874 DataArrayInt *MEDCouplingUMesh::getCellIdsFullyIncludedInNodeIds(const int *partBg, const int *partEnd) const
1876 std::vector<int> cellIdsKept;
1877 fillCellIdsToKeepFromNodeIds(partBg,partEnd,true,cellIdsKept);
1878 DataArrayInt *ret=DataArrayInt::New();
1879 ret->alloc((int)cellIdsKept.size(),1);
1880 std::copy(cellIdsKept.begin(),cellIdsKept.end(),ret->getPointer());
1885 * Keeps from 'this' only cells which constituing point id are in the ids specified by ['begin','end').
1886 * The resulting cell ids are stored at the end of the 'cellIdsKept' parameter.
1887 * Parameter 'fullyIn' specifies if a cell that has part of its nodes in ids array is kept or not.
1888 * If 'fullyIn' is true only cells whose ids are \b fully contained in ['begin','end') tab will be kept.
1890 * @param begin input start of array of node ids.
1891 * @param end input end of array of node ids.
1892 * @param fullyIn input that specifies if all node ids must be in ['begin','end') array to consider cell to be in.
1893 * @param cellIdsKept in/out array where all candidate cell ids are put at the end.
1895 void MEDCouplingUMesh::fillCellIdsToKeepFromNodeIds(const int *begin, const int *end, bool fullyIn, std::vector<int>& cellIdsKept) const
1897 std::set<int> fastFinder(begin,end);
1898 int nbOfCells=getNumberOfCells();
1899 const int *conn=getNodalConnectivity()->getConstPointer();
1900 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
1901 for(int i=0;i<nbOfCells;i++)
1903 std::set<int> connOfCell(conn+connIndex[i]+1,conn+connIndex[i+1]);
1904 connOfCell.erase(-1);//polyhedron separator
1905 int refLgth=(int)connOfCell.size();
1906 std::set<int> locMerge;
1907 std::insert_iterator< std::set<int> > it(locMerge,locMerge.begin());
1908 std::set_intersection(connOfCell.begin(),connOfCell.end(),fastFinder.begin(),fastFinder.end(),it);
1909 if(((int)locMerge.size()==refLgth && fullyIn) || (locMerge.size()!=0 && !fullyIn))
1910 cellIdsKept.push_back(i);
1915 * This method is very close too MEDCouplingUMesh::buildPartOfMySelfNode. The difference is that it returns directly ids.
1917 DataArrayInt *MEDCouplingUMesh::getCellIdsLyingOnNodes(const int *begin, const int *end, bool fullyIn) const
1919 std::vector<int> cellIdsKept;
1920 fillCellIdsToKeepFromNodeIds(begin,end,fullyIn,cellIdsKept);
1921 DataArrayInt *ret=DataArrayInt::New();
1922 ret->alloc((int)cellIdsKept.size(),1);
1923 std::copy(cellIdsKept.begin(),cellIdsKept.end(),ret->getPointer());
1924 ret->setName(getName());
1929 * Keeps from 'this' only cells which constituing point id are in the ids specified by ['begin','end').
1930 * The return newly allocated mesh will share the same coordinates as 'this'.
1931 * Parameter 'fullyIn' specifies if a cell that has part of its nodes in ids array is kept or not.
1932 * If 'fullyIn' is true only cells whose ids are \b fully contained in ['begin','end') tab will be kept.
1934 MEDCouplingPointSet *MEDCouplingUMesh::buildPartOfMySelfNode(const int *begin, const int *end, bool fullyIn) const
1936 std::vector<int> cellIdsKept;
1937 fillCellIdsToKeepFromNodeIds(begin,end,fullyIn,cellIdsKept);
1938 return buildPartOfMySelf(&cellIdsKept[0],&cellIdsKept[0]+cellIdsKept.size(),true);
1942 * Contrary to MEDCouplingUMesh::buildPartOfMySelfNode method this method builds a mesh with a meshDimension equal to
1943 * this->getMeshDimension()-1. The return newly allocated mesh will share the same coordinates as 'this'.
1944 * Parameter 'fullyIn' specifies if a face that has part of its nodes in ids array is kept or not.
1945 * If 'fullyIn' is true only faces whose ids are \b fully contained in ['begin','end') tab will be kept.
1947 MEDCouplingPointSet *MEDCouplingUMesh::buildFacePartOfMySelfNode(const int *begin, const int *end, bool fullyIn) const
1949 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> desc,descIndx,revDesc,revDescIndx;
1950 desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=DataArrayInt::New(); revDescIndx=DataArrayInt::New();
1951 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
1952 desc=0; descIndx=0; revDesc=0; revDescIndx=0;
1953 return subMesh->buildPartOfMySelfNode(begin,end,fullyIn);
1957 * This method returns a mesh with meshDim=this->getMeshDimension()-1.
1958 * This returned mesh contains cells that are linked with one and only one cell of this.
1959 * @param keepCoords specifies if ParaMEDMEM::MEDCouplingUMesh::zipCoords is called on returned mesh before being returned. If true zipCoords is \b NOT called, if false, zipCoords is called.
1960 * @return mesh with ref counter equal to 1.
1962 MEDCouplingPointSet *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
1964 DataArrayInt *desc=DataArrayInt::New();
1965 DataArrayInt *descIndx=DataArrayInt::New();
1966 DataArrayInt *revDesc=DataArrayInt::New();
1967 DataArrayInt *revDescIndx=DataArrayInt::New();
1969 MEDCouplingUMesh *meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
1972 descIndx->decrRef();
1973 int nbOfCells=meshDM1->getNumberOfCells();
1974 const int *revDescIndxC=revDescIndx->getConstPointer();
1975 std::vector<int> boundaryCells;
1976 for(int i=0;i<nbOfCells;i++)
1977 if(revDescIndxC[i+1]-revDescIndxC[i]==1)
1978 boundaryCells.push_back(i);
1979 revDescIndx->decrRef();
1980 MEDCouplingPointSet *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
1986 * This method returns a newly created DataArrayInt instance containing ids of cells located in boundary.
1987 * A cell is detected to be on boundary if it contains one or more than one face having only one father.
1988 * This method makes the assumption that 'this' is fully defined (coords,connectivity). If not an exception will be thrown.
1990 DataArrayInt *MEDCouplingUMesh::findCellIdsOnBoundary() const throw(INTERP_KERNEL::Exception)
1992 checkFullyDefined();
1993 DataArrayInt *desc=DataArrayInt::New();
1994 DataArrayInt *descIndx=DataArrayInt::New();
1995 DataArrayInt *revDesc=DataArrayInt::New();
1996 DataArrayInt *revDescIndx=DataArrayInt::New();
1998 MEDCouplingUMesh *meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2001 descIndx->decrRef();
2003 DataArrayInt *tmp=revDescIndx->deltaShiftIndex();
2004 DataArrayInt *faceIds=tmp->getIdsEqual(1);
2006 int nbOfFaces=faceIds->getNumberOfTuples();
2007 const int *faces=faceIds->getConstPointer();
2009 for(const int *w=faces;w!=faces+nbOfFaces;w++)
2010 ret.insert(revDesc->getIJ(revDescIndx->getIJ(*w,0),0));
2013 revDescIndx->decrRef();
2016 DataArrayInt *ret2=DataArrayInt::New();
2017 ret2->alloc((int)ret.size(),1);
2018 std::copy(ret.begin(),ret.end(),ret2->getPointer());
2019 ret2->setName("BoundaryCells");
2024 * This method find in \b this cells ids that lie on mesh \b otherDimM1OnSameCoords.
2025 * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2026 * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2027 * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2029 * s0 is the cells ids set in \b this lying on at least one node in fetched nodes in \b otherDimM1OnSameCoords.
2030 * This method method returns cells ids set s = s1 + s2 where :
2032 * - s1 are cells ids in \b this whose dim-1 constituent equals a cell in \b otherDimM1OnSameCoords.
2033 * - s2 are cells ids in \b s0 - \b s1 whose at least two neighbors are in s1.
2035 * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2036 * are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2038 * \param [out] cellIdsRk0 a newly allocated array containing cells ids in \b this containg s0 in above algorithm.
2039 * \param [out] cellIdsRk1 a newly allocated array containing cells ids of s1+s2 \b into \b cellIdsRk0 subset. To get absolute ids of s1+s2 simply invoke
2040 * cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2042 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *&cellIdsRk0, DataArrayInt *&cellIdsRk1) const throw(INTERP_KERNEL::Exception)
2044 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2045 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2046 checkConnectivityFullyDefined();
2047 otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2048 if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2049 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2050 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2051 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2052 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2053 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> descThisPart=DataArrayInt::New(),descIThisPart=DataArrayInt::New(),revDescThisPart=DataArrayInt::New(),revDescIThisPart=DataArrayInt::New();
2054 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2055 const int *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2056 DataArrayInt *idsOtherInConsti=0;
2057 bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2058 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> idsOtherInConstiAuto(idsOtherInConsti);
2060 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2062 for(const int *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2063 s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2064 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> s1arr_renum1=DataArrayInt::New(); s1arr_renum1->alloc((int)s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2065 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> s1Comparr_renum1=s1arr_renum1->buildComplement(s0arr->getNumberOfTuples());
2066 DataArrayInt *neighThisPart=0,*neighIThisPart=0;
2067 ComputeNeighborsOfCellsAdv(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart,neighThisPart,neighIThisPart);
2068 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> neighThisPartAuto(neighThisPart),neighIThisPartAuto(neighIThisPart);
2069 ExtractFromIndexedArrays(s1Comparr_renum1->begin(),s1Comparr_renum1->end(),neighThisPart,neighIThisPart,neighThisPart,neighIThisPart);// reuse of neighThisPart and neighIThisPart
2070 neighThisPartAuto=neighThisPart; neighIThisPartAuto=neighIThisPart;
2071 RemoveIdsFromIndexedArrays(s1Comparr_renum1->begin(),s1Comparr_renum1->end(),neighThisPart,neighIThisPart);
2072 neighThisPartAuto=0;
2073 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> s2_tmp=neighIThisPart->deltaShiftIndex();
2074 const int li[2]={0,1};
2075 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> s2_renum2=s2_tmp->getIdsNotEqualList(li,li+2);
2076 s2_renum2->transformWithIndArr(s1Comparr_renum1->begin(),s1Comparr_renum1->end());//s2_renum2==s2_renum1
2077 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> s_renum1=DataArrayInt::Aggregate(s2_renum2,s1arr_renum1,0);
2080 s0arr->incrRef(); cellIdsRk0=s0arr;
2081 s_renum1->incrRef(); cellIdsRk1=s_renum1;
2085 * 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
2086 * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2088 * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2090 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const throw(INTERP_KERNEL::Exception)
2092 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> desc=DataArrayInt::New();
2093 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> descIndx=DataArrayInt::New();
2094 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revDesc=DataArrayInt::New();
2095 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revDescIndx=DataArrayInt::New();
2097 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2098 revDesc=0; desc=0; descIndx=0;
2099 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revDescIndx2=revDescIndx->deltaShiftIndex();
2100 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> part=revDescIndx2->getIdsEqual(1);
2101 return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2105 * This methods returns set of nodes in a newly allocated array that the caller has to deal with.
2106 * The returned nodes ids are those lying on the boundary of \b this.
2108 DataArrayInt *MEDCouplingUMesh::findBoundaryNodes() const
2110 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> skin=computeSkin();
2111 return skin->computeFetchedNodeIds();
2114 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const throw(INTERP_KERNEL::Exception)
2117 return const_cast<MEDCouplingUMesh *>(this);
2121 * This method renumber 'this' using 'newNodeNumbers' array of size this->getNumberOfNodes.
2122 * newNbOfNodes specifies the *std::max_element(newNodeNumbers,newNodeNumbers+this->getNumberOfNodes())
2123 * This value is asked because often known by the caller of this method.
2124 * This method, contrary to MEDCouplingMesh::renumberCells does NOT conserve the number of nodes before and after.
2126 * @param newNodeNumbers array specifying the new numbering in old2New convention.
2127 * @param newNbOfNodes the new number of nodes.
2129 void MEDCouplingUMesh::renumberNodes(const int *newNodeNumbers, int newNbOfNodes)
2131 MEDCouplingPointSet::renumberNodes(newNodeNumbers,newNbOfNodes);
2132 renumberNodesInConn(newNodeNumbers);
2136 * This method renumber 'this' using 'newNodeNumbers' array of size this->getNumberOfNodes.
2137 * newNbOfNodes specifies the *std::max_element(newNodeNumbers,newNodeNumbers+this->getNumberOfNodes())
2138 * This value is asked because often known by the caller of this method.
2139 * This method, contrary to MEDCouplingMesh::renumberCells does NOT conserve the number of nodes before and after.
2140 * The difference with ParaMEDMEM::MEDCouplingUMesh::renumberNodes method is in the fact that the barycenter of merged nodes is computed here.
2142 * @param newNodeNumbers array specifying the new numbering.
2143 * @param newNbOfNodes the new number of nodes.
2146 void MEDCouplingUMesh::renumberNodes2(const int *newNodeNumbers, int newNbOfNodes)
2148 MEDCouplingPointSet::renumberNodes2(newNodeNumbers,newNbOfNodes);
2149 renumberNodesInConn(newNodeNumbers);
2153 * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2154 * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2155 * 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.
2156 * 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.
2157 * 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.
2159 * \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
2160 * parameter is altered during the call.
2161 * \param [out] nodeIdsToDuplicate node ids needed to be duplicated following the algorithm explain above.
2162 * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2163 * \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.
2165 * \warning This method modifies param \b otherDimM1OnSameCoords (for speed reasons).
2167 void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *& nodeIdsToDuplicate,
2168 DataArrayInt *& cellIdsNeededToBeRenum, DataArrayInt *& cellIdsNotModified) const throw(INTERP_KERNEL::Exception)
2170 checkFullyDefined();
2171 otherDimM1OnSameCoords.checkFullyDefined();
2172 if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2173 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2174 if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2175 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2176 DataArrayInt *cellIdsRk0=0,*cellIdsRk1=0;
2177 findCellIdsLyingOn(otherDimM1OnSameCoords,cellIdsRk0,cellIdsRk1);
2178 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cellIdsRk0Auto(cellIdsRk0),cellIdsRk1Auto(cellIdsRk1);
2179 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> s0=cellIdsRk1->buildComplement(cellIdsRk0->getNumberOfTuples());
2180 s0->transformWithIndArr(cellIdsRk0Auto->begin(),cellIdsRk0Auto->end());
2181 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m0Part=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0->begin(),s0->end(),true));
2182 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> s1=m0Part->computeFetchedNodeIds();
2183 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> s2=otherDimM1OnSameCoords.computeFetchedNodeIds();
2184 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> s3=s2->buildSubstraction(s1);
2185 cellIdsRk1->transformWithIndArr(cellIdsRk0Auto->begin(),cellIdsRk0Auto->end());
2187 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m0Part2=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellIdsRk1->begin(),cellIdsRk1->end(),true));
2188 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> desc00=DataArrayInt::New(),descI00=DataArrayInt::New(),revDesc00=DataArrayInt::New(),revDescI00=DataArrayInt::New();
2189 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00);
2190 DataArrayInt *idsTmp=0;
2191 bool b=m01->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsTmp);
2192 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ids(idsTmp);
2194 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the given mdim-1 mesh in other is not a constituent of this !");
2195 MEDCouplingUMesh::RemoveIdsFromIndexedArrays(ids->begin(),ids->end(),desc00,descI00);
2196 DataArrayInt *tmp0=0,*tmp1=0;
2197 ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00,tmp0,tmp1);
2198 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> neigh00(tmp0);
2199 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> neighI00(tmp1);
2200 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cellsToModifyConn0_torenum=MEDCouplingUMesh::ComputeSpreadZoneGradually(neigh00,neighI00);
2201 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cellsToModifyConn1_torenum=cellsToModifyConn0_torenum->buildComplement(neighI00->getNumberOfTuples()-1);
2202 cellsToModifyConn0_torenum->transformWithIndArr(cellIdsRk1->begin(),cellIdsRk1->end());
2203 cellsToModifyConn1_torenum->transformWithIndArr(cellIdsRk1->begin(),cellIdsRk1->end());
2205 cellIdsNeededToBeRenum=cellsToModifyConn0_torenum; cellsToModifyConn0_torenum->incrRef();
2206 cellIdsNotModified=cellsToModifyConn1_torenum; cellsToModifyConn1_torenum->incrRef();
2207 nodeIdsToDuplicate=s3; s3->incrRef();
2211 * This method operates a modification of the connectivity and coords in \b this.
2212 * Every time that a node id in [\b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd) will append in nodal connectivity of \b this
2213 * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2214 * 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
2215 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2216 * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2218 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2220 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2221 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2223 void MEDCouplingUMesh::duplicateNodes(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd) throw(INTERP_KERNEL::Exception)
2225 int nbOfNodes=getNumberOfNodes();
2226 duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2227 duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2231 * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2232 * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2233 * This method is an generalization of \ref ParaMEDMEM::MEDCouplingUMesh::shiftNodeNumbersInConn "shiftNodeNumbersInConn method".
2234 * @param [in] newNodeNumbers in old2New convention
2236 void MEDCouplingUMesh::renumberNodesInConn(const int *newNodeNumbersO2N)
2238 checkConnectivityFullyDefined();
2239 int *conn=getNodalConnectivity()->getPointer();
2240 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2241 int nbOfCells=getNumberOfCells();
2242 for(int i=0;i<nbOfCells;i++)
2243 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2245 int& node=conn[iconn];
2246 if(node>=0)//avoid polyhedron separator
2248 node=newNodeNumbersO2N[node];
2251 _nodal_connec->declareAsNew();
2256 * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2257 * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2258 * This method is an specialization of \ref ParaMEDMEM::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2260 * @param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2262 void MEDCouplingUMesh::shiftNodeNumbersInConn(int delta) throw(INTERP_KERNEL::Exception)
2264 checkConnectivityFullyDefined();
2265 int *conn=getNodalConnectivity()->getPointer();
2266 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2267 int nbOfCells=getNumberOfCells();
2268 for(int i=0;i<nbOfCells;i++)
2269 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2271 int& node=conn[iconn];
2272 if(node>=0)//avoid polyhedron separator
2277 _nodal_connec->declareAsNew();
2282 * This method operates a modification of the connectivity in \b this.
2283 * 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.
2284 * Every time that a node id in [\b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd) will append in nodal connectivity of \b this
2285 * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2286 * 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
2287 * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2288 * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2290 * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2291 * As an another consequense after the call of this method \b this can be transiently non cohrent.
2293 * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2294 * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2295 * \param [in] offset the offset applied to all node ids in connectivity that are in [nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd).
2297 void MEDCouplingUMesh::duplicateNodesInConn(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd, int offset) throw(INTERP_KERNEL::Exception)
2299 checkConnectivityFullyDefined();
2300 std::map<int,int> m;
2302 for(const int *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2304 int *conn=getNodalConnectivity()->getPointer();
2305 const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2306 int nbOfCells=getNumberOfCells();
2307 for(int i=0;i<nbOfCells;i++)
2308 for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2310 int& node=conn[iconn];
2311 if(node>=0)//avoid polyhedron separator
2313 std::map<int,int>::iterator it=m.find(node);
2322 * This method renumbers cells of 'this' using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2324 * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2325 * After the call of this method the number of cells remains the same as before.
2327 * If 'check' equals true the method will check that any elements in [old2NewBg;old2NewEnd) is unique ; if not
2328 * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [old2NewBg;old2NewEnd) is not expected to
2329 * be strictly in [0;this->getNumberOfCells()).
2331 * If 'check' equals false the method will not check the content of [old2NewBg;old2NewEnd).
2332 * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [old2NewBg;old2NewEnd) should be unique and
2333 * should be contained in[0;this->getNumberOfCells()).
2335 * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2337 void MEDCouplingUMesh::renumberCells(const int *old2NewBg, bool check) throw(INTERP_KERNEL::Exception)
2339 checkConnectivityFullyDefined();
2340 int nbCells=getNumberOfCells();
2341 const int *array=old2NewBg;
2343 array=DataArrayInt::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2345 const int *conn=_nodal_connec->getConstPointer();
2346 const int *connI=_nodal_connec_index->getConstPointer();
2347 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newConn=DataArrayInt::New();
2348 newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2349 newConn->copyStringInfoFrom(*_nodal_connec);
2350 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newConnI=DataArrayInt::New();
2351 newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2352 newConnI->copyStringInfoFrom(*_nodal_connec_index);
2354 int *newC=newConn->getPointer();
2355 int *newCI=newConnI->getPointer();
2358 for(int i=0;i<nbCells;i++)
2360 std::size_t pos=std::distance(array,std::find(array,array+nbCells,i));
2361 int nbOfElts=connI[pos+1]-connI[pos];
2362 newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2367 setConnectivity(newConn,newConnI);
2369 delete [] const_cast<int *>(array);
2373 * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox'.
2374 * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2375 * added in 'elems' parameter.
2377 void MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps, std::vector<int>& elems) const
2379 if(getMeshDimension()==-1)
2384 int dim=getSpaceDimension();
2385 double* elem_bb=new double[2*dim];
2386 const int* conn = getNodalConnectivity()->getConstPointer();
2387 const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2388 const double* coords = getCoords()->getConstPointer();
2389 int nbOfCells=getNumberOfCells();
2390 for ( int ielem=0; ielem<nbOfCells;ielem++ )
2392 for (int i=0; i<dim; i++)
2394 elem_bb[i*2]=std::numeric_limits<double>::max();
2395 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2398 for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2400 int node= conn[inode];
2401 if(node>=0)//avoid polyhedron separator
2403 for (int idim=0; idim<dim; idim++)
2405 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2407 elem_bb[idim*2] = coords[node*dim+idim] ;
2409 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2411 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2416 if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2418 elems.push_back(ielem);
2425 * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2426 * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2427 * added in 'elems' parameter.
2429 void MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps, std::vector<int>& elems)
2431 if(getMeshDimension()==-1)
2436 int dim=getSpaceDimension();
2437 double* elem_bb=new double[2*dim];
2438 const int* conn = getNodalConnectivity()->getConstPointer();
2439 const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2440 const double* coords = getCoords()->getConstPointer();
2441 int nbOfCells=getNumberOfCells();
2442 for ( int ielem=0; ielem<nbOfCells;ielem++ )
2444 for (int i=0; i<dim; i++)
2446 elem_bb[i*2]=std::numeric_limits<double>::max();
2447 elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2450 for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2452 int node= conn[inode];
2453 if(node>=0)//avoid polyhedron separator
2455 for (int idim=0; idim<dim; idim++)
2457 if ( coords[node*dim+idim] < elem_bb[idim*2] )
2459 elem_bb[idim*2] = coords[node*dim+idim] ;
2461 if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2463 elem_bb[idim*2+1] = coords[node*dim+idim] ;
2468 if (intersectsBoundingBox(bbox, elem_bb, dim, eps))
2470 elems.push_back(ielem);
2477 * Returns the cell type of cell with id 'cellId'.
2479 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(int cellId) const
2481 const int *ptI=_nodal_connec_index->getConstPointer();
2482 const int *pt=_nodal_connec->getConstPointer();
2483 if(cellId>=0 && cellId<_nodal_connec_index->getNbOfElems()-1)
2484 return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2487 std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2488 throw INTERP_KERNEL::Exception(oss.str().c_str());
2493 * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2494 * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2495 * The coordinates array is not considered here.
2497 * \param [in] type the geometric type
2500 DataArrayInt *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const throw(INTERP_KERNEL::Exception)
2504 checkConnectivityFullyDefined();
2505 int nbCells=getNumberOfCells();
2506 int mdim=getMeshDimension();
2507 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
2508 if(mdim!=(int)cm.getDimension())
2509 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
2510 const int *ptI=_nodal_connec_index->getConstPointer();
2511 const int *pt=_nodal_connec->getConstPointer();
2512 for(int i=0;i<nbCells;i++)
2514 if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
2517 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret=DataArrayInt::New(); ret->alloc((int)v.size(),1);
2518 std::copy(v.begin(),v.end(),ret->getPointer());
2524 * Returns nb of cells having the geometric type 'type'.
2526 int MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2528 const int *ptI=_nodal_connec_index->getConstPointer();
2529 const int *pt=_nodal_connec->getConstPointer();
2530 int nbOfCells=getNumberOfCells();
2532 for(int i=0;i<nbOfCells;i++)
2533 if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
2539 * Appends the nodal connectivity in 'conn' of cell with id 'cellId'.
2540 * All elements added in conn can be used by MEDCouplingUMesh::getCoordinatesOfNode method.
2541 * That is to say -1 separator is omitted in returned conn.
2543 void MEDCouplingUMesh::getNodeIdsOfCell(int cellId, std::vector<int>& conn) const
2545 const int *ptI=_nodal_connec_index->getConstPointer();
2546 const int *pt=_nodal_connec->getConstPointer();
2547 for(const int *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
2552 std::string MEDCouplingUMesh::simpleRepr() const
2554 static const char msg0[]="No coordinates specified !";
2555 std::ostringstream ret;
2556 ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
2557 ret << "Description of mesh : \"" << getDescription() << "\"\n";
2559 double tt=getTime(tmpp1,tmpp2);
2560 ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
2561 ret << "Iteration : " << tmpp1 << " Order : " << tmpp2 << "\n";
2562 ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : ";
2565 const int spaceDim=getSpaceDimension();
2566 ret << spaceDim << "\nInfo attached on space dimension : ";
2567 for(int i=0;i<spaceDim;i++)
2568 ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
2572 ret << msg0 << "\n";
2573 ret << "Number of nodes : ";
2575 ret << getNumberOfNodes() << "\n";
2577 ret << msg0 << "\n";
2578 ret << "Number of cells : ";
2579 if(_nodal_connec!=0 && _nodal_connec_index!=0)
2580 ret << getNumberOfCells() << "\n";
2582 ret << "No connectivity specified !" << "\n";
2583 ret << "Cell types present : ";
2584 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
2586 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
2587 ret << cm.getRepr() << " ";
2593 std::string MEDCouplingUMesh::advancedRepr() const
2595 std::ostringstream ret;
2596 ret << simpleRepr();
2597 ret << "\nCoordinates array : \n___________________\n\n";
2599 _coords->reprWithoutNameStream(ret);
2601 ret << "No array set !\n";
2602 ret << "\n\nConnectivity arrays : \n_____________________\n\n";
2603 reprConnectivityOfThisLL(ret);
2608 * This method returns a C++ code that is a dump of \a this.
2609 * This method will throw if this is not fully defined.
2611 std::string MEDCouplingUMesh::cppRepr() const throw(INTERP_KERNEL::Exception)
2613 static const char coordsName[]="coords";
2614 static const char connName[]="conn";
2615 static const char connIName[]="connI";
2616 checkFullyDefined();
2617 std::ostringstream ret; ret << "// coordinates" << std::endl;
2618 _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
2619 _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
2620 _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
2621 ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
2622 ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
2623 ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
2624 ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
2628 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
2630 std::ostringstream ret;
2631 reprConnectivityOfThisLL(ret);
2636 * This method builds a newly allocated instance (with the same name than 'this') that the caller has the responsability to deal with.
2637 * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
2638 * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
2641 * This method expects that 'this' has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
2642 * This method analyzes the 3 arrays of 'this'. For each the following behaviour is done : if the array is null a newly one is created
2643 * with number of tuples set to 0, if not the array is taken as this in the returned instance.
2645 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(int spaceDim) const throw(INTERP_KERNEL::Exception)
2647 int mdim=getMeshDimension();
2649 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
2650 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
2651 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp1,tmp2;
2652 bool needToCpyCT=true;
2655 tmp1=DataArrayInt::New(); tmp1->alloc(0,1);
2663 if(!_nodal_connec_index)
2665 tmp2=DataArrayInt::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
2670 tmp2=_nodal_connec_index;
2673 ret->setConnectivity(tmp1,tmp2,false);
2678 MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
2679 ret->setCoords(coords);
2682 ret->setCoords(_coords);
2687 void MEDCouplingUMesh::reprConnectivityOfThisLL(std::ostringstream& stream) const
2689 if(_nodal_connec!=0 && _nodal_connec_index!=0)
2691 int nbOfCells=getNumberOfCells();
2692 const int *c=_nodal_connec->getConstPointer();
2693 const int *ci=_nodal_connec_index->getConstPointer();
2694 for(int i=0;i<nbOfCells;i++)
2696 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[i]]);
2697 stream << "Cell #" << i << " " << cm.getRepr() << " : ";
2698 std::copy(c+ci[i]+1,c+ci[i+1],std::ostream_iterator<int>(stream," "));
2703 stream << "Connectivity not defined !\n";
2706 int MEDCouplingUMesh::getNumberOfNodesInCell(int cellId) const
2708 const int *ptI=_nodal_connec_index->getConstPointer();
2709 const int *pt=_nodal_connec->getConstPointer();
2710 if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
2711 return ptI[cellId+1]-ptI[cellId]-1;
2713 return (int)std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind2nd(std::not_equal_to<int>(),-1));
2717 * This method is equivalent to MEDCouplingUMesh::getAllTypes excecpt that it returns only types of submesh which cell ids are in [begin,end).
2718 * This method avoids to compute explicitely submesh to get its types.
2720 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const int *begin, const int *end) const throw(INTERP_KERNEL::Exception)
2722 checkFullyDefined();
2723 std::set<INTERP_KERNEL::NormalizedCellType> ret;
2724 const int *conn=_nodal_connec->getConstPointer();
2725 const int *connIndex=_nodal_connec_index->getConstPointer();
2726 for(const int *w=begin;w!=end;w++)
2727 ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
2732 * Method reserved for advanced users having prepared their connectivity before.
2733 * Arrays 'conn' and 'connIndex' will be aggregated without any copy and their counter will be incremented.
2735 void MEDCouplingUMesh::setConnectivity(DataArrayInt *conn, DataArrayInt *connIndex, bool isComputingTypes)
2737 DataArrayInt::SetArrayIn(conn,_nodal_connec);
2738 DataArrayInt::SetArrayIn(connIndex,_nodal_connec_index);
2739 if(isComputingTypes)
2745 * Copy constructor. If 'deepCpy' is false 'this' is a shallow copy of other.
2746 * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
2748 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCopy):MEDCouplingPointSet(other,deepCopy),_iterator(-1),_mesh_dim(other._mesh_dim),
2749 _nodal_connec(0),_nodal_connec_index(0),
2750 _types(other._types)
2752 if(other._nodal_connec)
2753 _nodal_connec=other._nodal_connec->performCpy(deepCopy);
2754 if(other._nodal_connec_index)
2755 _nodal_connec_index=other._nodal_connec_index->performCpy(deepCopy);
2758 MEDCouplingUMesh::~MEDCouplingUMesh()
2761 _nodal_connec->decrRef();
2762 if(_nodal_connec_index)
2763 _nodal_connec_index->decrRef();
2767 * This method recomputes all cell types of 'this'.
2769 void MEDCouplingUMesh::computeTypes()
2771 if(_nodal_connec && _nodal_connec_index)
2774 const int *conn=_nodal_connec->getConstPointer();
2775 const int *connIndex=_nodal_connec_index->getConstPointer();
2776 int nbOfElem=_nodal_connec_index->getNbOfElems()-1;
2777 for(const int *pt=connIndex;pt!=connIndex+nbOfElem;pt++)
2778 _types.insert((INTERP_KERNEL::NormalizedCellType)conn[*pt]);
2783 * This method checks that all arrays are set. If yes nothing done if no an exception is thrown.
2785 void MEDCouplingUMesh::checkFullyDefined() const throw(INTERP_KERNEL::Exception)
2787 if(!_nodal_connec_index || !_nodal_connec || !_coords)
2788 throw INTERP_KERNEL::Exception("Reverse nodal connectivity computation requires full connectivity and coordinates set in unstructured mesh.");
2792 * This method checks that all connectivity arrays are set. If yes nothing done if no an exception is thrown.
2794 void MEDCouplingUMesh::checkConnectivityFullyDefined() const throw(INTERP_KERNEL::Exception)
2796 if(!_nodal_connec_index || !_nodal_connec)
2797 throw INTERP_KERNEL::Exception("Reverse nodal connectivity computation requires full connectivity set in unstructured mesh.");
2800 int MEDCouplingUMesh::getNumberOfCells() const
2802 if(_nodal_connec_index)
2804 return _nodal_connec_index->getNumberOfTuples()-1;
2811 throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
2814 int MEDCouplingUMesh::getMeshDimension() const
2817 throw INTERP_KERNEL::Exception("No mesh dimension specified !");
2822 * This method is for test reason. Normally the integer returned is not useable by user.
2824 int MEDCouplingUMesh::getMeshLength() const
2826 return _nodal_connec->getNbOfElems();
2830 * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
2832 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<int>& tinyInfo, std::vector<std::string>& littleStrings) const
2834 MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
2835 tinyInfo.push_back(getMeshDimension());
2836 tinyInfo.push_back(getNumberOfCells());
2838 tinyInfo.push_back(getMeshLength());
2840 tinyInfo.push_back(-1);
2844 * First step of unserialization process.
2846 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<int>& tinyInfo) const
2848 return tinyInfo[6]<=0;
2852 * Second step of serialization process.
2853 * @param tinyInfo must be equal to the result given by getTinySerializationInformation method.
2855 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<int>& tinyInfo, DataArrayInt *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
2857 MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
2859 a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
2863 * Third and final step of serialization process.
2865 void MEDCouplingUMesh::serialize(DataArrayInt *&a1, DataArrayDouble *&a2) const
2867 MEDCouplingPointSet::serialize(a1,a2);
2868 if(getMeshDimension()>-1)
2870 a1=DataArrayInt::New();
2871 a1->alloc(getMeshLength()+getNumberOfCells()+1,1);
2872 int *ptA1=a1->getPointer();
2873 const int *conn=getNodalConnectivity()->getConstPointer();
2874 const int *index=getNodalConnectivityIndex()->getConstPointer();
2875 ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
2876 std::copy(conn,conn+getMeshLength(),ptA1);
2883 * Second and final unserialization process.
2884 * @param tinyInfo must be equal to the result given by getTinySerializationInformation method.
2886 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<int>& tinyInfo, const DataArrayInt *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
2888 MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
2889 setMeshDimension(tinyInfo[5]);
2893 const int *recvBuffer=a1->getConstPointer();
2894 DataArrayInt* myConnecIndex=DataArrayInt::New();
2895 myConnecIndex->alloc(tinyInfo[6]+1,1);
2896 std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
2897 DataArrayInt* myConnec=DataArrayInt::New();
2898 myConnec->alloc(tinyInfo[7],1);
2899 std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
2900 setConnectivity(myConnec, myConnecIndex) ;
2901 myConnec->decrRef();
2902 myConnecIndex->decrRef();
2907 * This is the low algorithm of MEDCouplingUMesh::buildPartOfMySelf2.
2908 * CellIds are given using range specified by a start an end and step.
2910 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfKeepCoords2(int start, int end, int step) const
2912 checkFullyDefined();
2913 int ncell=getNumberOfCells();
2914 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret=MEDCouplingUMesh::New();
2915 ret->_mesh_dim=_mesh_dim;
2916 ret->setCoords(_coords);
2917 int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfKeepCoords2 : ");
2918 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(newNbOfCells+1,1);
2919 int *newConnIPtr=newConnI->getPointer(); *newConnIPtr=0;
2921 const int *conn=_nodal_connec->getConstPointer();
2922 const int *connIndex=_nodal_connec_index->getConstPointer();
2923 for(int i=0;i<newNbOfCells;i++,newConnIPtr++,work+=step)
2925 if(work>=0 && work<ncell)
2927 newConnIPtr[1]=newConnIPtr[0]+connIndex[work+1]-connIndex[work];
2931 std::ostringstream oss; oss << "MEDCouplingUMesh::buildPartOfMySelfKeepCoords2 : On pos #" << i << " input cell id =" << work << " should be in [0," << ncell << ") !";
2932 throw INTERP_KERNEL::Exception(oss.str().c_str());
2935 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(newConnIPtr[0],1);
2936 int *newConnPtr=newConn->getPointer();
2937 std::set<INTERP_KERNEL::NormalizedCellType> types;
2939 for(int i=0;i<newNbOfCells;i++,newConnIPtr++,work+=step)
2941 types.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[work]]);
2942 newConnPtr=std::copy(conn+connIndex[work],conn+connIndex[work+1],newConnPtr);
2944 ret->setConnectivity(newConn,newConnI,false);
2946 ret->copyTinyInfoFrom(this);
2947 std::string name(getName());
2948 std::size_t sz=strlen(PART_OF_NAME);
2949 if(name.length()>=sz)
2950 name=name.substr(0,sz);
2951 if(name!=PART_OF_NAME)
2953 std::ostringstream stream; stream << PART_OF_NAME << getName();
2954 ret->setName(stream.str().c_str());
2957 ret->setName(getName());
2963 * This is the low algorithm of MEDCouplingUMesh::buildPartOfMySelf.
2964 * Keeps from 'this' only cells which constituing point id are in the ids specified by ['begin','end').
2965 * The return newly allocated mesh will share the same coordinates as 'this'.
2967 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfKeepCoords(const int *begin, const int *end) const
2969 checkFullyDefined();
2970 int ncell=getNumberOfCells();
2971 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret=MEDCouplingUMesh::New();
2972 ret->_mesh_dim=_mesh_dim;
2973 ret->setCoords(_coords);
2974 std::size_t nbOfElemsRet=std::distance(begin,end);
2975 int *connIndexRet=new int[nbOfElemsRet+1];
2977 const int *conn=_nodal_connec->getConstPointer();
2978 const int *connIndex=_nodal_connec_index->getConstPointer();
2980 for(const int *work=begin;work!=end;work++,newNbring++)
2982 if(*work>=0 && *work<ncell)
2983 connIndexRet[newNbring+1]=connIndexRet[newNbring]+connIndex[*work+1]-connIndex[*work];
2986 delete [] connIndexRet;
2987 std::ostringstream oss; oss << "MEDCouplingUMesh::buildPartOfMySelfKeepCoords : On pos #" << std::distance(begin,work) << " input cell id =" << *work << " should be in [0," << ncell << ") !";
2988 throw INTERP_KERNEL::Exception(oss.str().c_str());
2991 int *connRet=new int[connIndexRet[nbOfElemsRet]];
2992 int *connRetWork=connRet;
2993 std::set<INTERP_KERNEL::NormalizedCellType> types;
2994 for(const int *work=begin;work!=end;work++)
2996 types.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*work]]);
2997 connRetWork=std::copy(conn+connIndex[*work],conn+connIndex[*work+1],connRetWork);
2999 DataArrayInt *connRetArr=DataArrayInt::New();
3000 connRetArr->useArray(connRet,true,CPP_DEALLOC,connIndexRet[nbOfElemsRet],1);
3001 DataArrayInt *connIndexRetArr=DataArrayInt::New();
3002 connIndexRetArr->useArray(connIndexRet,true,CPP_DEALLOC,(int)nbOfElemsRet+1,1);
3003 ret->setConnectivity(connRetArr,connIndexRetArr,false);
3005 connRetArr->decrRef();
3006 connIndexRetArr->decrRef();
3007 ret->copyTinyInfoFrom(this);
3008 std::string name(getName());
3009 std::size_t sz=strlen(PART_OF_NAME);
3010 if(name.length()>=sz)
3011 name=name.substr(0,sz);
3012 if(name!=PART_OF_NAME)
3014 std::ostringstream stream; stream << PART_OF_NAME << getName();
3015 ret->setName(stream.str().c_str());
3018 ret->setName(getName());
3024 * brief returns the volumes of the cells underlying the field \a field
3026 * For 2D geometries, the returned field contains the areas.
3027 * For 3D geometries, the returned field contains the volumes.
3029 * param field field on which cells the volumes are required
3030 * return field containing the volumes, area or length depending the meshdimension.
3032 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3034 std::string name="MeasureOfMesh_";
3036 int nbelem=getNumberOfCells();
3037 MEDCouplingFieldDouble *field=MEDCouplingFieldDouble::New(ON_CELLS);
3038 field->setName(name.c_str());
3039 DataArrayDouble* array=DataArrayDouble::New();
3040 array->alloc(nbelem,1);
3041 double *area_vol=array->getPointer();
3042 field->setArray(array) ;
3044 field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3045 if(getMeshDimension()!=-1)
3048 INTERP_KERNEL::NormalizedCellType type;
3049 int dim_space=getSpaceDimension();
3050 const double *coords=getCoords()->getConstPointer();
3051 const int *connec=getNodalConnectivity()->getConstPointer();
3052 const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3053 for(int iel=0;iel<nbelem;iel++)
3055 ipt=connec_index[iel];
3056 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3057 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);
3060 std::transform(area_vol,area_vol+nbelem,area_vol,std::ptr_fun<double,double>(fabs));
3064 area_vol[0]=std::numeric_limits<double>::max();
3070 * This method is equivalent to MEDCouplingUMesh::getMeasureField except that only part defined by [begin,end) is returned !
3071 * This method avoids to build explicitely part of this to perform the work.
3073 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const int *begin, const int *end) const
3075 std::string name="PartMeasureOfMesh_";
3077 int nbelem=(int)std::distance(begin,end);
3078 DataArrayDouble* array=DataArrayDouble::New();
3079 array->setName(name.c_str());
3080 array->alloc(nbelem,1);
3081 double *area_vol=array->getPointer();
3082 if(getMeshDimension()!=-1)
3085 INTERP_KERNEL::NormalizedCellType type;
3086 int dim_space=getSpaceDimension();
3087 const double *coords=getCoords()->getConstPointer();
3088 const int *connec=getNodalConnectivity()->getConstPointer();
3089 const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3090 for(const int *iel=begin;iel!=end;iel++)
3092 ipt=connec_index[*iel];
3093 type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3094 *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<int,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3097 std::transform(array->getPointer(),area_vol,array->getPointer(),std::ptr_fun<double,double>(fabs));
3101 area_vol[0]=std::numeric_limits<double>::max();
3107 * This methods returns a field on nodes and no time. This method is usefull to check "P1*" conservative interpolators.
3108 * This field returns the getMeasureField of the dualMesh in P1 sens of 'this'.
3110 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3112 MEDCouplingFieldDouble *tmp=getMeasureField(isAbs);
3113 std::string name="MeasureOnNodeOfMesh_";
3115 int nbNodes=getNumberOfNodes();
3116 MEDCouplingFieldDouble *ret=MEDCouplingFieldDouble::New(ON_NODES);
3117 double cst=1./((double)getMeshDimension()+1.);
3118 DataArrayDouble* array=DataArrayDouble::New();
3119 array->alloc(nbNodes,1);
3120 double *valsToFill=array->getPointer();
3121 std::fill(valsToFill,valsToFill+nbNodes,0.);
3122 const double *values=tmp->getArray()->getConstPointer();
3123 DataArrayInt *da=DataArrayInt::New();
3124 DataArrayInt *daInd=DataArrayInt::New();
3125 getReverseNodalConnectivity(da,daInd);
3126 const int *daPtr=da->getConstPointer();
3127 const int *daIPtr=daInd->getConstPointer();
3128 for(int i=0;i<nbNodes;i++)
3129 for(const int *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3130 valsToFill[i]+=cst*values[*cell];
3134 ret->setArray(array);
3141 * This methods returns a vector field on cells that represents the orthogonal vector normalized of each 2D cell of this.
3142 * This method is only callable on mesh with meshdim == 2 and spacedim==2 or 3.
3144 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3146 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3147 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3148 MEDCouplingFieldDouble *ret=MEDCouplingFieldDouble::New(ON_CELLS,NO_TIME);
3149 DataArrayDouble *array=DataArrayDouble::New();
3150 int nbOfCells=getNumberOfCells();
3151 int nbComp=getMeshDimension()+1;
3152 array->alloc(nbOfCells,nbComp);
3153 double *vals=array->getPointer();
3154 const int *connI=_nodal_connec_index->getConstPointer();
3155 const int *conn=_nodal_connec->getConstPointer();
3156 const double *coords=_coords->getConstPointer();
3157 if(getMeshDimension()==2)
3159 if(getSpaceDimension()==3)
3161 DataArrayDouble *loc=getBarycenterAndOwner();
3162 const double *locPtr=loc->getConstPointer();
3163 for(int i=0;i<nbOfCells;i++,vals+=3)
3165 int offset=connI[i];
3166 INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3167 double n=INTERP_KERNEL::norm<3>(vals);
3168 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3174 for(int i=0;i<nbOfCells;i++)
3175 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3178 else//meshdimension==1
3181 for(int i=0;i<nbOfCells;i++)
3183 int offset=connI[i];
3184 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3185 double n=INTERP_KERNEL::norm<2>(tmp);
3186 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3191 ret->setArray(array);
3198 * This method is equivalent to MEDCouplingUMesh::buildOrthogonalField except that only part defined by [begin,end) is returned !
3199 * This method avoids to build explicitely part of this to perform the work.
3201 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const int *begin, const int *end) const
3203 if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3204 throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3205 MEDCouplingFieldDouble *ret=MEDCouplingFieldDouble::New(ON_CELLS,NO_TIME);
3206 DataArrayDouble *array=DataArrayDouble::New();
3207 std::size_t nbelems=std::distance(begin,end);
3208 int nbComp=getMeshDimension()+1;
3209 array->alloc((int)nbelems,nbComp);
3210 double *vals=array->getPointer();
3211 const int *connI=_nodal_connec_index->getConstPointer();
3212 const int *conn=_nodal_connec->getConstPointer();
3213 const double *coords=_coords->getConstPointer();
3214 if(getMeshDimension()==2)
3216 if(getSpaceDimension()==3)
3218 DataArrayDouble *loc=getPartBarycenterAndOwner(begin,end);
3219 const double *locPtr=loc->getConstPointer();
3220 for(const int *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3222 int offset=connI[*i];
3223 INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3224 double n=INTERP_KERNEL::norm<3>(vals);
3225 std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3231 for(std::size_t i=0;i<nbelems;i++)
3232 { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3235 else//meshdimension==1
3238 for(const int *i=begin;i!=end;i++)
3240 int offset=connI[*i];
3241 std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3242 double n=INTERP_KERNEL::norm<2>(tmp);
3243 std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3248 ret->setArray(array);
3255 * This methods returns a vector newly created field on cells that represents the direction vector of each 1D cell of this.
3256 * This method is only callable on mesh with meshdim == 1 containing only SEG2.
3258 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3260 if(getMeshDimension()!=1)
3261 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3262 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3263 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3264 MEDCouplingFieldDouble *ret=MEDCouplingFieldDouble::New(ON_CELLS,NO_TIME);
3265 DataArrayDouble *array=DataArrayDouble::New();
3266 int nbOfCells=getNumberOfCells();
3267 int spaceDim=getSpaceDimension();
3268 array->alloc(nbOfCells,spaceDim);
3269 double *pt=array->getPointer();
3270 const double *coo=getCoords()->getConstPointer();
3271 std::vector<int> conn;
3273 for(int i=0;i<nbOfCells;i++)
3276 getNodeIdsOfCell(i,conn);
3277 pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3279 ret->setArray(array);
3286 * This method expects that 'this' is fully defined and has a spaceDim==3 and a meshDim==3. If it is not the case an exception will be thrown.
3287 * This method returns 2 objects :
3288 * - a newly created mesh instance containing the result of the slice lying on different coords than 'this' and with a meshdim == 2
3289 * - a newly created dataarray having number of tuples equal to the number of cells in returned mesh that tells for each 2D cell in returned
3290 * mesh the 3D cell id is 'this' it comes from.
3291 * This method works only for linear meshes (non quadratic).
3292 * If plane crosses within 'eps' a face in 'this' shared by more than 1 cell, 2 output faces will be generated. The 2 faces having the same geometry than intersecting
3293 * face. Only 'cellIds' parameter can distinguish the 2.
3294 * @param origin is the origin of the plane. It should be an array of length 3.
3295 * @param vec is the direction vector of the plane. It should be an array of length 3. Norm of 'vec' should be > 1e-6.
3296 * @param eps is the precision. It is used by called method MEDCouplingUMesh::getCellIdsCrossingPlane for the first 3D cell selection (in absolute). 'eps' is
3297 * also used to state if new points should be created or already existing points are reused. 'eps' is also used to tells if plane overlaps a face, edge or nodes (in absolute).
3299 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const throw(INTERP_KERNEL::Exception)
3301 checkFullyDefined();
3302 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3303 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3304 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3305 if(candidates->empty())
3306 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3307 std::vector<int> nodes;
3308 std::vector<int> cellIds2D,cellIds1D;
3309 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3310 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3311 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> desc1=DataArrayInt::New(),desc2=DataArrayInt::New();
3312 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> descIndx1=DataArrayInt::New(),descIndx2=DataArrayInt::New();
3313 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revDesc1=DataArrayInt::New(),revDesc2=DataArrayInt::New();
3314 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revDescIndx1=DataArrayInt::New(),revDescIndx2=DataArrayInt::New();
3315 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3316 revDesc2=0; revDescIndx2=0;
3317 mDesc2->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds2D);
3318 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3319 revDesc1=0; revDescIndx1=0;
3320 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3322 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3323 for(std::vector<int>::const_iterator it=cellIds1D.begin();it!=cellIds1D.end();it++)
3325 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3326 std::vector< std::pair<int,int> > cut3DSurf(mDesc2->getNumberOfCells());
3327 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3328 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3329 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3330 std::vector<int> conn,connI,cellIds2;
3332 subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3333 if(cellIds2.empty())
3334 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3335 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3336 ret->setCoords(mDesc1->getCoords());
3337 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> c=DataArrayInt::New();
3338 c->alloc((int)conn.size(),1); std::copy(conn.begin(),conn.end(),c->getPointer());
3339 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cI=DataArrayInt::New();
3340 cI->alloc((int)connI.size(),1); std::copy(connI.begin(),connI.end(),cI->getPointer());
3341 ret->setConnectivity(c,cI,true);
3342 cellIds=candidates->selectByTupleId(&cellIds2[0],&cellIds2[0]+cellIds2.size());
3348 * This method expects that 'this' is fully defined and has a spaceDim==3 and a meshDim==2. If it is not the case an exception will be thrown.
3349 * This method returns 2 objects :
3350 * - a newly created mesh instance containing the result of the slice lying on different coords than 'this' and with a meshdim == 1
3351 * - a newly created dataarray having number of tuples equal to the number of cells in returned mesh that tells for each 2D cell in returned
3352 * mesh the 3DSurf cell id is 'this' it comes from.
3353 * This method works only for linear meshes (non quadratic).
3354 * If plane crosses within 'eps' a face in 'this' shared by more than 1 cell, 2 output faces will be generated. The 2 faces having the same geometry than intersecting
3355 * face. Only 'cellIds' parameter can distinguish the 2.
3356 * @param origin is the origin of the plane. It should be an array of length 3.
3357 * @param vec is the direction vector of the plane. It should be an array of length 3. Norm of 'vec' should be > 1e-6.
3358 * @param eps is the precision. It is used by called method MEDCouplingUMesh::getCellIdsCrossingPlane for the first 3DSurf cell selection (in absolute). 'eps' is
3359 * also used to state if new points should be created or already existing points are reused. 'eps' is also used to tells if plane overlaps a face, edge or nodes (in absolute).
3361 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const throw(INTERP_KERNEL::Exception)
3363 checkFullyDefined();
3364 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3365 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3366 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3367 if(candidates->empty())
3368 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3369 std::vector<int> nodes;
3370 std::vector<int> cellIds1D;
3371 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3372 subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3373 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> desc1=DataArrayInt::New();
3374 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> descIndx1=DataArrayInt::New();
3375 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revDesc1=DataArrayInt::New();
3376 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revDescIndx1=DataArrayInt::New();
3377 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> mDesc1=subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3378 mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3380 std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3381 for(std::vector<int>::const_iterator it=cellIds1D.begin();it!=cellIds1D.end();it++)
3383 mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3384 int ncellsSub=subMesh->getNumberOfCells();
3385 std::vector< std::pair<int,int> > cut3DSurf(ncellsSub);
3386 AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3387 mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3388 desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3389 std::vector<int> conn,connI,cellIds2; connI.push_back(0);
3390 const int *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3391 const int *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3392 for(int i=0;i<ncellsSub;i++)
3394 if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3396 if(cut3DSurf[i].first!=-2)
3398 conn.push_back((int)INTERP_KERNEL::NORM_SEG2); conn.push_back(cut3DSurf[i].first); conn.push_back(cut3DSurf[i].second);
3399 connI.push_back((int)conn.size());
3400 cellIds2.push_back(i);
3404 int cellId3DSurf=cut3DSurf[i].second;
3405 int offset=nodalI[cellId3DSurf]+1;
3406 int nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3407 for(int j=0;j<nbOfEdges;j++)
3409 conn.push_back((int)INTERP_KERNEL::NORM_SEG2); conn.push_back(nodal[offset+j]); conn.push_back(nodal[offset+(j+1)%nbOfEdges]);
3410 connI.push_back((int)conn.size());
3411 cellIds2.push_back(cellId3DSurf);
3416 if(cellIds2.empty())
3417 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3418 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3419 ret->setCoords(mDesc1->getCoords());
3420 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> c=DataArrayInt::New();
3421 c->alloc((int)conn.size(),1); std::copy(conn.begin(),conn.end(),c->getPointer());
3422 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cI=DataArrayInt::New();
3423 cI->alloc((int)connI.size(),1); std::copy(connI.begin(),connI.end(),cI->getPointer());
3424 ret->setConnectivity(c,cI,true);
3425 cellIds=candidates->selectByTupleId(&cellIds2[0],&cellIds2[0]+cellIds2.size());
3431 * This method expects that 'this' is fully defined and has a spaceDim==3. If it is not the case an exception will be thrown.
3432 * This method returns a newly created dataarray containing cellsids in 'this' that potentially crosses the plane specified by 'origin' and 'vec'.
3433 * @param origin is the origin of the plane. It should be an array of length 3.
3434 * @param vec is the direction vector of the plane. It should be an array of length 3. Norm of 'vec' should be > 1e-6.
3436 DataArrayInt *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const throw(INTERP_KERNEL::Exception)
3438 checkFullyDefined();
3439 if(getSpaceDimension()!=3)
3440 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
3441 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
3443 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
3445 vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
3446 double angle=acos(vec[2]/normm);
3447 std::vector<int> cellIds;
3451 MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> coo=_coords->deepCpy();
3452 MEDCouplingPointSet::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer());
3453 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
3455 mw->getBoundingBox(bbox);
3456 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3457 mw->getCellsInBoundingBox(bbox,eps,cellIds);
3461 getBoundingBox(bbox);
3462 bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3463 getCellsInBoundingBox(bbox,eps,cellIds);
3465 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret=DataArrayInt::New();
3466 ret->alloc((int)cellIds.size(),1);
3467 std::copy(cellIds.begin(),cellIds.end(),ret->getPointer());
3473 * This method checks that 'this' is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
3474 * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
3475 * No consideration of coordinate is done by this method.
3476 * 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)
3477 * If not false is returned. In case that false is returned a call to ParaMEDMEM::MEDCouplingUMesh::mergeNodes could be usefull.
3479 bool MEDCouplingUMesh::isContiguous1D() const throw(INTERP_KERNEL::Exception)
3481 if(getMeshDimension()!=1)
3482 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
3483 int nbCells=getNumberOfCells();
3485 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
3486 const int *connI=_nodal_connec_index->getConstPointer();
3487 const int *conn=_nodal_connec->getConstPointer();
3488 int ref=conn[connI[0]+2];
3489 for(int i=1;i<nbCells;i++)
3491 if(conn[connI[i]+1]!=ref)
3493 ref=conn[connI[i]+2];
3499 * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
3500 * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
3501 * @param pt reference point of the line
3502 * @param v normalized director vector of the line
3503 * @param eps max precision before throwing an exception
3504 * @param res output of size this->getNumberOfCells
3506 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
3508 if(getMeshDimension()!=1)
3509 throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
3510 if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3511 throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
3512 if(getSpaceDimension()!=3)
3513 throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
3514 MEDCouplingFieldDouble *f=buildDirectionVectorField();
3515 const double *fPtr=f->getArray()->getConstPointer();
3517 for(int i=0;i<getNumberOfCells();i++)
3519 const double *tmp1=fPtr+3*i;
3520 tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
3521 tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
3522 tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
3523 double n1=INTERP_KERNEL::norm<3>(tmp);
3524 n1/=INTERP_KERNEL::norm<3>(tmp1);
3528 throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
3531 const double *coo=getCoords()->getConstPointer();
3532 for(int i=0;i<getNumberOfNodes();i++)
3534 std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
3535 std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
3536 res[i]=std::accumulate(tmp,tmp+3,0.);
3542 * Returns a cell if any that contains the point located on 'pos' with precison eps.
3543 * If 'pos' is outside 'this' -1 is returned. If several cells contain this point the cell with the smallest id is returned.
3544 * \b Warning this method is good if the caller intends to evaluate only one point. But if more than one point is requested on 'this'
3545 * it is better to use MEDCouplingUMesh::getCellsContainingPoints method because in this case, the acceleration structure will be computed only once.
3547 int MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
3549 std::vector<int> elts;
3550 getCellsContainingPoint(pos,eps,elts);
3553 return elts.front();
3557 * Returns all cellIds in 'elts' of point 'pos' with eps accuracy.
3558 * \b Warning this method is good if the caller intends to evaluate only one point. But if more than one point is requested on 'this'
3559 * it is better to use MEDCouplingUMesh::getCellsContainingPoints method because in this case, the acceleration structure will be computed only once.
3561 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<int>& elts) const
3563 std::vector<int> eltsIndex;
3564 getCellsContainingPoints(pos,1,eps,elts,eltsIndex);
3569 namespace ParaMEDMEM
3571 template<const int SPACEDIMM>
3575 static const int MY_SPACEDIM=SPACEDIMM;
3576 static const int MY_MESHDIM=8;
3577 typedef int MyConnType;
3578 static const INTERP_KERNEL::NumberingPolicy My_numPol=INTERP_KERNEL::ALL_C_MODE;
3580 // useless, but for windows compilation ...
3581 const double* getCoordinatesPtr() const { return 0; }
3582 const int* getConnectivityPtr() const { return 0; }
3583 const int* getConnectivityIndexPtr() const { return 0; }
3584 INTERP_KERNEL::NormalizedCellType getTypeOfElement(int) const { return (INTERP_KERNEL::NormalizedCellType)0; }
3588 INTERP_KERNEL::Edge *MEDCouplingUMeshBuildQPFromEdge(INTERP_KERNEL::NormalizedCellType typ, std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >& mapp2, const int *bg)
3590 INTERP_KERNEL::Edge *ret=0;
3593 case INTERP_KERNEL::NORM_SEG2:
3595 ret=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[1]].first);
3598 case INTERP_KERNEL::NORM_SEG3:
3600 INTERP_KERNEL::EdgeLin *e1=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[2]].first);
3601 INTERP_KERNEL::EdgeLin *e2=new INTERP_KERNEL::EdgeLin(mapp2[bg[2]].first,mapp2[bg[1]].first);
3602 INTERP_KERNEL::SegSegIntersector inters(*e1,*e2);
3603 bool colinearity=inters.areColinears();
3604 delete e1; delete e2;
3606 ret=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[1]].first);
3608 ret=new INTERP_KERNEL::EdgeArcCircle(mapp2[bg[0]].first,mapp2[bg[2]].first,mapp2[bg[1]].first);
3609 mapp2[bg[2]].second=false;
3613 throw INTERP_KERNEL::Exception("MEDCouplingUMeshBuildQPFromEdge : Expecting a mesh with spaceDim==2 and meshDim==1 !");
3619 * This method creates a sub mesh in Geometric2D DS. The sub mesh is composed be the sub set of cells in 'candidates' and the global mesh 'mDesc'.
3620 * The input meth 'mDesc' must be so that mDim==1 et spaceDim==3.
3621 * 'mapp' contains a mapping between local numbering in submesh and the global node numbering in 'mDesc'.
3623 INTERP_KERNEL::QuadraticPolygon *MEDCouplingUMeshBuildQPFromMesh(const MEDCouplingUMesh *mDesc, const std::vector<int>& candidates, std::map<INTERP_KERNEL::Node *,int>& mapp) throw(INTERP_KERNEL::Exception)
3626 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.
3627 const double *coo=mDesc->getCoords()->getConstPointer();
3628 const int *c=mDesc->getNodalConnectivity()->getConstPointer();
3629 const int *cI=mDesc->getNodalConnectivityIndex()->getConstPointer();
3631 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
3632 s.insert(c+cI[*it]+1,c+cI[(*it)+1]);
3633 for(std::set<int>::const_iterator it2=s.begin();it2!=s.end();it2++)
3635 INTERP_KERNEL::Node *n=new INTERP_KERNEL::Node(coo[2*(*it2)],coo[2*(*it2)+1]);
3636 mapp2[*it2]=std::pair<INTERP_KERNEL::Node *,bool>(n,true);
3638 INTERP_KERNEL::QuadraticPolygon *ret=new INTERP_KERNEL::QuadraticPolygon;
3639 for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
3641 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[*it]];
3642 ret->pushBack(MEDCouplingUMeshBuildQPFromEdge(typ,mapp2,c+cI[*it]+1));
3644 for(std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >::const_iterator it2=mapp2.begin();it2!=mapp2.end();it2++)
3646 if((*it2).second.second)
3647 mapp[(*it2).second.first]=(*it2).first;
3648 ((*it2).second.first)->decrRef();
3653 INTERP_KERNEL::Node *MEDCouplingUMeshBuildQPNode(int nodeId, const double *coo1, int offset1, const double *coo2, int offset2, const std::vector<double>& addCoo)
3657 int locId=nodeId-offset2;
3658 return new INTERP_KERNEL::Node(addCoo[2*locId],addCoo[2*locId+1]);
3662 int locId=nodeId-offset1;
3663 return new INTERP_KERNEL::Node(coo2[2*locId],coo2[2*locId+1]);
3665 return new INTERP_KERNEL::Node(coo1[2*nodeId],coo1[2*nodeId+1]);
3668 void MEDCouplingUMeshBuildQPFromMesh3(const double *coo1, int offset1, const double *coo2, int offset2, const std::vector<double>& addCoo,
3669 const int *desc1Bg, const int *desc1End, const std::vector<std::vector<int> >& intesctEdges1,
3670 /*output*/std::map<INTERP_KERNEL::Node *,int>& mapp, std::map<int,INTERP_KERNEL::Node *>& mappRev)
3672 for(const int *desc1=desc1Bg;desc1!=desc1End;desc1++)
3674 int eltId1=abs(*desc1)-1;
3675 for(std::vector<int>::const_iterator it1=intesctEdges1[eltId1].begin();it1!=intesctEdges1[eltId1].end();it1++)
3677 std::map<int,INTERP_KERNEL::Node *>::const_iterator it=mappRev.find(*it1);
3678 if(it==mappRev.end())
3680 INTERP_KERNEL::Node *node=MEDCouplingUMeshBuildQPNode(*it1,coo1,offset1,coo2,offset2,addCoo);
3691 template<int SPACEDIM>
3692 void MEDCouplingUMesh::getCellsContainingPointsAlg(const double *coords, const double *pos, int nbOfPoints,
3693 double eps, std::vector<int>& elts, std::vector<int>& eltsIndex) const
3695 std::vector<double> bbox;
3696 eltsIndex.resize(nbOfPoints+1);
3699 getBoundingBoxForBBTree(bbox);
3700 int nbOfCells=getNumberOfCells();
3701 const int *conn=_nodal_connec->getConstPointer();
3702 const int *connI=_nodal_connec_index->getConstPointer();
3703 double bb[2*SPACEDIM];
3704 BBTree<SPACEDIM,int> myTree(&bbox[0],0,0,nbOfCells,-eps);
3705 for(int i=0;i<nbOfPoints;i++)
3707 eltsIndex[i+1]=eltsIndex[i];
3708 for(int j=0;j<SPACEDIM;j++)
3710 bb[2*j]=pos[SPACEDIM*i+j];
3711 bb[2*j+1]=pos[SPACEDIM*i+j];
3713 std::vector<int> candidates;
3714 myTree.getIntersectingElems(bb,candidates);
3715 for(std::vector<int>::const_iterator iter=candidates.begin();iter!=candidates.end();iter++)
3717 int sz=connI[(*iter)+1]-connI[*iter]-1;
3718 if(INTERP_KERNEL::PointLocatorAlgos<DummyClsMCUG<SPACEDIM> >::isElementContainsPoint(pos+i*SPACEDIM,
3719 (INTERP_KERNEL::NormalizedCellType)conn[connI[*iter]],
3720 coords,conn+connI[*iter]+1,sz,eps))
3723 elts.push_back(*iter);
3730 * This method is an extension of MEDCouplingUMesh::getCellContainingPoint and MEDCouplingUMesh::getCellsContainingPoint.
3731 * This method performs 'nbOfPoints' time the getCellsContainingPoint request. This method is recommended rather than the 2 others
3732 * in case of multi points searching.
3733 * This method returns 2 arrays 'elts' and 'eltsIndex'. 'eltsIndex' is of size 'nbOfPoints+1' and 'elts' is of size 'eltsIndex[nbOfPoints-1]'.
3734 * For point j in [0,nbOfPoints), (eltsIndex[j+1]-eltsIndex[j]) cells contain this point. These cells are : [elts.begin()+eltsIndex[j],elts.begin():eltsIndex[j+1]).
3736 * \param pos input parameter that points to an array of size 'getSpaceDim()*nbOfPoints' points stored in full interlace mode : X0,Y0,Z0,X1,Y1,Z1...
3738 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, int nbOfPoints, double eps,
3739 std::vector<int>& elts, std::vector<int>& eltsIndex) const
3741 int spaceDim=getSpaceDimension();
3742 int mDim=getMeshDimension();
3747 const double *coords=_coords->getConstPointer();
3748 getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
3755 throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
3757 else if(spaceDim==2)
3761 const double *coords=_coords->getConstPointer();
3762 getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
3765 throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
3767 else if(spaceDim==1)
3771 const double *coords=_coords->getConstPointer();
3772 getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
3775 throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
3778 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
3782 * This method is only available for a mesh with meshDim==2 and spaceDim==2||spaceDim==3.
3783 * This method returns a vector 'cells' where all detected butterfly cells have been added to cells.
3784 * A 2D cell is considered to be butterfly if it exists at least one pair of distinct edges of it that intersect each other
3785 * anywhere excepted their extremities. An INTERP_KERNEL::NORM_NORI3 could \b not be butterfly.
3787 void MEDCouplingUMesh::checkButterflyCells(std::vector<int>& cells, double eps) const
3789 const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
3790 if(getMeshDimension()!=2)
3791 throw INTERP_KERNEL::Exception(msg);
3792 int spaceDim=getSpaceDimension();
3793 if(spaceDim!=2 && spaceDim!=3)
3794 throw INTERP_KERNEL::Exception(msg);
3795 const int *conn=_nodal_connec->getConstPointer();
3796 const int *connI=_nodal_connec_index->getConstPointer();
3797 int nbOfCells=getNumberOfCells();
3798 std::vector<double> cell2DinS2;
3799 for(int i=0;i<nbOfCells;i++)
3801 int offset=connI[i];
3802 int nbOfNodesForCell=connI[i+1]-offset-1;
3803 if(nbOfNodesForCell<=3)
3805 bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
3806 project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
3807 if(isButterfly2DCell(cell2DinS2,isQuad,eps))
3814 * This method is typically requested to unbutterfly 2D linear cells in \b this.
3816 * 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.
3817 * 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.
3819 * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
3820 * This convex envelop is computed using Jarvis march algorithm.
3821 * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
3822 * 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)
3823 * 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.
3825 * @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.
3827 DataArrayInt *MEDCouplingUMesh::convexEnvelop2D() throw(INTERP_KERNEL::Exception)
3829 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
3830 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D works only for meshDim=2 and spaceDim=2 !");
3831 checkFullyDefined();
3832 const double *coords=getCoords()->getConstPointer();
3833 int nbOfCells=getNumberOfCells();
3834 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> nodalConnecIndexOut=DataArrayInt::New();
3835 nodalConnecIndexOut->alloc(nbOfCells+1,1);
3836 std::vector<int> nodalConnecOut;
3837 int *workIndexOut=nodalConnecIndexOut->getPointer();
3839 const int *nodalConnecIn=_nodal_connec->getConstPointer();
3840 const int *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
3841 std::set<INTERP_KERNEL::NormalizedCellType> types;
3842 std::vector<int> isChanged;
3843 for(int i=0;i<nbOfCells;i++,workIndexOut++)
3845 std::size_t pos=nodalConnecOut.size();
3846 if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
3847 isChanged.push_back(i);
3848 types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut[pos]);
3849 workIndexOut[1]=(int)nodalConnecOut.size();
3851 if(isChanged.empty())
3853 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> nodalConnecOut2=DataArrayInt::New();
3854 nodalConnecOut2->alloc((int)nodalConnecOut.size(),1);
3855 std::copy(nodalConnecOut.begin(),nodalConnecOut.end(),nodalConnecOut2->getPointer());
3856 setConnectivity(nodalConnecOut2,nodalConnecIndexOut,false);
3858 DataArrayInt *ret=DataArrayInt::New(); ret->alloc((int)isChanged.size(),1);
3859 std::copy(isChanged.begin(),isChanged.end(),ret->getPointer());
3864 * This method is expected to be applied on a mesh with spaceDim==3 and meshDim==3. If not an exception will be thrown.
3865 * This method analyzes only linear extruded 3D cells (NORM_HEXA8,NORM_PENTA6,NORM_HEXGP12...)
3866 * If some extruded cells does not fulfill the MED norm for extruded cells (first face of 3D cell should be oriented to the exterior of the 3D cell).
3867 * Some viewers are very careful of that (SMESH), but ParaVis ignore that.
3869 void MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells(std::vector<int>& cells) throw(INTERP_KERNEL::Exception)
3871 const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
3872 if(getMeshDimension()!=3)
3873 throw INTERP_KERNEL::Exception(msg);
3874 int spaceDim=getSpaceDimension();
3876 throw INTERP_KERNEL::Exception(msg);
3878 int nbOfCells=getNumberOfCells();
3879 int *conn=_nodal_connec->getPointer();
3880 const int *connI=_nodal_connec_index->getConstPointer();
3881 const double *coo=getCoords()->getConstPointer();
3882 double vec0[3],vec1[3];
3883 for(int i=0;i<nbOfCells;i++)
3885 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
3886 if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
3888 INTERP_KERNEL::AutoPtr<int> tmp=new int[connI[i+1]-connI[i]-1];
3889 int nbOfNodes=cm.fillSonCellNodalConnectivity(0,conn+connI[i]+1,tmp);
3890 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(tmp,nbOfNodes,coo,vec0);
3891 const double *pt0=coo+3*conn[connI[i]+1];
3892 const double *pt1=coo+3*conn[connI[i]+nbOfNodes+1];
3893 vec1[0]=pt0[0]-pt1[0]; vec1[1]=pt0[1]-pt1[1]; vec1[2]=pt0[2]-pt1[2];
3894 double dot=vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2];
3898 std::copy(conn+connI[i]+1,conn+connI[i+1],(int *)tmp);
3899 for(int j=1;j<nbOfNodes;j++)
3901 conn[connI[i]+1+j]=tmp[nbOfNodes-j];
3902 conn[connI[i]+1+j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
3910 * This method is \b NOT const because it can modify 'this'.
3911 * 'this' is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
3912 * @param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
3913 * @param policy specifies the type of extrusion chosen. \b 0 for translation (most simple),
3914 * \b 1 for translation and rotation around point of 'mesh1D'.
3915 * @return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than 'this'.
3917 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
3919 checkFullyDefined();
3920 mesh1D->checkFullyDefined();
3921 if(!mesh1D->isContiguous1D())
3922 throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
3923 if(getSpaceDimension()!=mesh1D->getSpaceDimension())
3924 throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same dimension !");
3925 if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3926 throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
3927 if(mesh1D->getMeshDimension()!=1)
3928 throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
3930 if(isPresenceOfQuadratic())
3932 if(mesh1D->isFullyQuadratic())
3935 throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
3938 int oldNbOfNodes=getNumberOfNodes();
3939 DataArrayDouble *newCoords=0;
3944 newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
3949 newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
3953 throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
3955 setCoords(newCoords);
3956 newCoords->decrRef();
3957 MEDCouplingUMesh *ret=buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad);
3963 * This method works on a 3D curve linear mesh that is to say (meshDim==1 and spaceDim==3).
3964 * If it is not the case an exception will be thrown.
3965 * This method is non const because the coordinate of 'this' can be appended with some new points issued from
3966 * intersection of plane defined by ('origin','vec').
3967 * This method has one in/out parameter : 'cut3DCurve'.
3968 * Param 'cut3DCurve' is expected to be of size 'this->getNumberOfCells()'. For each i in [0,'this->getNumberOfCells()')
3969 * if cut3DCurve[i]==-2, it means that for cell #i in 'this' nothing has been detected previously.
3970 * if cut3DCurve[i]==-1, it means that cell#i has been already detected to be fully part of plane defined by ('origin','vec').
3971 * This method will throw an exception if 'this' contains a non linear segment.
3973 void MEDCouplingUMesh::split3DCurveWithPlane(const double *origin, const double *vec, double eps, std::vector<int>& cut3DCurve) throw(INTERP_KERNEL::Exception)
3975 checkFullyDefined();
3976 if(getMeshDimension()!=1 || getSpaceDimension()!=3)
3977 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane works on umeshes with meshdim equal to 1 and spaceDim equal to 3 !");
3978 int ncells=getNumberOfCells();
3979 int nnodes=getNumberOfNodes();
3980 double vec2[3],vec3[3],vec4[3];
3981 double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
3983 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
3984 vec2[0]=vec[0]/normm; vec2[1]=vec[1]/normm; vec2[2]=vec[2]/normm;
3985 const int *conn=_nodal_connec->getConstPointer();
3986 const int *connI=_nodal_connec_index->getConstPointer();
3987 const double *coo=_coords->getConstPointer();
3988 std::vector<double> addCoo;
3989 for(int i=0;i<ncells;i++)
3991 if(conn[connI[i]]==(int)INTERP_KERNEL::NORM_SEG2)
3993 if(cut3DCurve[i]==-2)
3995 int st=conn[connI[i]+1],endd=conn[connI[i]+2];
3996 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];
3997 double normm2=sqrt(vec3[0]*vec3[0]+vec3[1]*vec3[1]+vec3[2]*vec3[2]);
3998 double colin=std::abs((vec3[0]*vec2[0]+vec3[1]*vec2[1]+vec3[2]*vec2[2])/normm2);
3999 if(colin>eps)//if colin<=eps -> current SEG2 is colinear to the input plane
4001 const double *st2=coo+3*st;
4002 vec4[0]=st2[0]-origin[0]; vec4[1]=st2[1]-origin[1]; vec4[2]=st2[2]-origin[2];
4003 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]));
4004 if(pos>eps && pos<1-eps)
4006 int nNode=((int)addCoo.size())/3;
4007 vec4[0]=st2[0]+pos*vec3[0]; vec4[1]=st2[1]+pos*vec3[1]; vec4[2]=st2[2]+pos*vec3[2];
4008 addCoo.insert(addCoo.end(),vec4,vec4+3);
4009 cut3DCurve[i]=nnodes+nNode;
4015 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane : this method is only available for linear cell (NORM_SEG2) !");
4019 int newNbOfNodes=nnodes+((int)addCoo.size())/3;
4020 MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> coo2=DataArrayDouble::New();
4021 coo2->alloc(newNbOfNodes,3);
4022 double *tmp=coo2->getPointer();
4023 tmp=std::copy(_coords->begin(),_coords->end(),tmp);
4024 std::copy(addCoo.begin(),addCoo.end(),tmp);
4025 DataArrayDouble::SetArrayIn(coo2,_coords);
4030 * This method incarnates the policy 0 for MEDCouplingUMesh::buildExtrudedMesh method.
4031 * @param mesh1D is the input 1D mesh used for translation computation.
4032 * @return newCoords new coords filled by this method.
4034 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslation(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4036 int oldNbOfNodes=getNumberOfNodes();
4037 int nbOf1DCells=mesh1D->getNumberOfCells();
4038 int spaceDim=getSpaceDimension();
4039 DataArrayDouble *ret=DataArrayDouble::New();
4040 std::vector<bool> isQuads;
4041 int nbOfLevsInVec=isQuad?2*nbOf1DCells+1:nbOf1DCells+1;
4042 ret->alloc(oldNbOfNodes*nbOfLevsInVec,spaceDim);
4043 double *retPtr=ret->getPointer();
4044 const double *coords=getCoords()->getConstPointer();
4045 double *work=std::copy(coords,coords+spaceDim*oldNbOfNodes,retPtr);
4047 std::vector<double> c;
4051 for(int i=0;i<nbOf1DCells;i++)
4054 mesh1D->getNodeIdsOfCell(i,v);
4056 mesh1D->getCoordinatesOfNode(v[isQuad?2:1],c);
4057 mesh1D->getCoordinatesOfNode(v[0],c);
4058 std::transform(c.begin(),c.begin()+spaceDim,c.begin()+spaceDim,vec,std::minus<double>());
4059 for(int j=0;j<oldNbOfNodes;j++)
4060 work=std::transform(vec,vec+spaceDim,retPtr+spaceDim*(i*oldNbOfNodes+j),work,std::plus<double>());
4064 mesh1D->getCoordinatesOfNode(v[1],c);
4065 mesh1D->getCoordinatesOfNode(v[0],c);
4066 std::transform(c.begin(),c.begin()+spaceDim,c.begin()+spaceDim,vec,std::minus<double>());
4067 for(int j=0;j<oldNbOfNodes;j++)
4068 work=std::transform(vec,vec+spaceDim,retPtr+spaceDim*(i*oldNbOfNodes+j),work,std::plus<double>());
4071 ret->copyStringInfoFrom(*getCoords());
4076 * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4077 * @param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4078 * @return newCoords new coords filled by this method.
4080 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation(const MEDCouplingUMesh *mesh1D, bool isQuad) const throw(INTERP_KERNEL::Exception)
4082 if(mesh1D->getSpaceDimension()==2)
4083 return fillExtCoordsUsingTranslAndAutoRotation2D(mesh1D,isQuad);
4084 if(mesh1D->getSpaceDimension()==3)
4085 return fillExtCoordsUsingTranslAndAutoRotation3D(mesh1D,isQuad);
4086 throw INTERP_KERNEL::Exception("Not implemented rotation and translation alg. for spacedim other than 2 and 3 !");
4090 * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4091 * @param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4092 * @return newCoords new coords filled by this method.
4094 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D(const MEDCouplingUMesh *mesh1D, bool isQuad) const throw(INTERP_KERNEL::Exception)
4097 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D : not implemented for quadratic cells !");
4098 int oldNbOfNodes=getNumberOfNodes();
4099 int nbOf1DCells=mesh1D->getNumberOfCells();
4101 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D : impossible to detect any angle of rotation ! Change extrusion policy 1->0 !");
4102 DataArrayDouble *ret=DataArrayDouble::New();
4103 int nbOfLevsInVec=nbOf1DCells+1;
4104 ret->alloc(oldNbOfNodes*nbOfLevsInVec,2);
4105 double *retPtr=ret->getPointer();
4106 retPtr=std::copy(getCoords()->getConstPointer(),getCoords()->getConstPointer()+getCoords()->getNbOfElems(),retPtr);
4107 MEDCouplingUMesh *tmp=MEDCouplingUMesh::New();
4108 DataArrayDouble *tmp2=getCoords()->deepCpy();
4109 tmp->setCoords(tmp2);
4111 const double *coo1D=mesh1D->getCoords()->getConstPointer();
4112 const int *conn1D=mesh1D->getNodalConnectivity()->getConstPointer();
4113 const int *connI1D=mesh1D->getNodalConnectivityIndex()->getConstPointer();
4114 for(int i=1;i<nbOfLevsInVec;i++)
4116 const double *begin=coo1D+2*conn1D[connI1D[i-1]+1];
4117 const double *end=coo1D+2*conn1D[connI1D[i-1]+2];
4118 const double *third=i+1<nbOfLevsInVec?coo1D+2*conn1D[connI1D[i]+2]:coo1D+2*conn1D[connI1D[i-2]+1];
4119 const double vec[2]={end[0]-begin[0],end[1]-begin[1]};
4120 tmp->translate(vec);
4121 double tmp3[2],radius,alpha,alpha0;
4122 const double *p0=i+1<nbOfLevsInVec?begin:third;
4123 const double *p1=i+1<nbOfLevsInVec?end:begin;
4124 const double *p2=i+1<nbOfLevsInVec?third:end;
4125 INTERP_KERNEL::EdgeArcCircle::GetArcOfCirclePassingThru(p0,p1,p2,tmp3,radius,alpha,alpha0);
4126 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]);
4127 double angle=acos(cosangle/(radius*radius));
4128 tmp->rotate(end,0,angle);
4129 retPtr=std::copy(tmp2->getConstPointer(),tmp2->getConstPointer()+tmp2->getNbOfElems(),retPtr);
4136 * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4137 * @param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4138 * @return newCoords new coords filled by this method.
4140 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D(const MEDCouplingUMesh *mesh1D, bool isQuad) const throw(INTERP_KERNEL::Exception)
4143 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D : not implemented for quadratic cells !");
4144 int oldNbOfNodes=getNumberOfNodes();
4145 int nbOf1DCells=mesh1D->getNumberOfCells();
4147 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D : impossible to detect any angle of rotation ! Change extrusion policy 1->0 !");
4148 DataArrayDouble *ret=DataArrayDouble::New();
4149 int nbOfLevsInVec=nbOf1DCells+1;
4150 ret->alloc(oldNbOfNodes*nbOfLevsInVec,3);
4151 double *retPtr=ret->getPointer();
4152 retPtr=std::copy(getCoords()->getConstPointer(),getCoords()->getConstPointer()+getCoords()->getNbOfElems(),retPtr);
4153 MEDCouplingUMesh *tmp=MEDCouplingUMesh::New();
4154 DataArrayDouble *tmp2=getCoords()->deepCpy();
4155 tmp->setCoords(tmp2);
4157 const double *coo1D=mesh1D->getCoords()->getConstPointer();
4158 const int *conn1D=mesh1D->getNodalConnectivity()->getConstPointer();
4159 const int *connI1D=mesh1D->getNodalConnectivityIndex()->getConstPointer();
4160 for(int i=1;i<nbOfLevsInVec;i++)
4162 const double *begin=coo1D+3*conn1D[connI1D[i-1]+1];
4163 const double *end=coo1D+3*conn1D[connI1D[i-1]+2];
4164 const double *third=i+1<nbOfLevsInVec?coo1D+3*conn1D[connI1D[i]+2]:coo1D+3*conn1D[connI1D[i-2]+1];
4165 const double vec[3]={end[0]-begin[0],end[1]-begin[1],end[2]-begin[2]};
4166 tmp->translate(vec);
4167 double tmp3[2],radius,alpha,alpha0;
4168 const double *p0=i+1<nbOfLevsInVec?begin:third;
4169 const double *p1=i+1<nbOfLevsInVec?end:begin;
4170 const double *p2=i+1<nbOfLevsInVec?third:end;
4171 double vecPlane[3]={
4172 (p1[1]-p0[1])*(p2[2]-p1[2])-(p1[2]-p0[2])*(p2[1]-p1[1]),
4173 (p1[2]-p0[2])*(p2[0]-p1[0])-(p1[0]-p0[0])*(p2[2]-p1[2]),
4174 (p1[0]-p0[0])*(p2[1]-p1[1])-(p1[1]-p0[1])*(p2[0]-p1[0]),
4176 double norm=sqrt(vecPlane[0]*vecPlane[0]+vecPlane[1]*vecPlane[1]+vecPlane[2]*vecPlane[2]);
4179 vecPlane[0]/=norm; vecPlane[1]/=norm; vecPlane[2]/=norm;
4180 double norm2=sqrt(vecPlane[0]*vecPlane[0]+vecPlane[1]*vecPlane[1]);
4181 double vec2[2]={vecPlane[1]/norm2,-vecPlane[0]/norm2};
4183 double c2=cos(asin(s2));
4185 {vec2[0]*vec2[0]*(1-c2)+c2, vec2[0]*vec2[1]*(1-c2), vec2[1]*s2},
4186 {vec2[0]*vec2[1]*(1-c2), vec2[1]*vec2[1]*(1-c2)+c2, -vec2[0]*s2},
4187 {-vec2[1]*s2, vec2[0]*s2, c2}
4189 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]};
4190 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]};
4191 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]};
4192 INTERP_KERNEL::EdgeArcCircle::GetArcOfCirclePassingThru(p0r,p1r,p2r,tmp3,radius,alpha,alpha0);
4193 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]);
4194 double angle=acos(cosangle/(radius*radius));
4195 tmp->rotate(end,vecPlane,angle);
4198 retPtr=std::copy(tmp2->getConstPointer(),tmp2->getConstPointer()+tmp2->getNbOfElems(),retPtr);
4205 * This method is private because not easy to use for end user. This method is const contrary to
4206 * MEDCouplingUMesh::buildExtrudedMesh method because this->_coords are expected to contain
4207 * the coords sorted slice by slice.
4208 * @param isQuad specifies presence of quadratic cells.
4210 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMeshFromThisLowLev(int nbOfNodesOf1Lev, bool isQuad) const
4212 int nbOf1DCells=getNumberOfNodes()/nbOfNodesOf1Lev-1;
4213 int nbOf2DCells=getNumberOfCells();
4214 int nbOf3DCells=nbOf2DCells*nbOf1DCells;
4215 MEDCouplingUMesh *ret=MEDCouplingUMesh::New("Extruded",getMeshDimension()+1);
4216 const int *conn=_nodal_connec->getConstPointer();
4217 const int *connI=_nodal_connec_index->getConstPointer();
4218 DataArrayInt *newConn=DataArrayInt::New();
4219 DataArrayInt *newConnI=DataArrayInt::New();
4220 newConnI->alloc(nbOf3DCells+1,1);
4221 int *newConnIPtr=newConnI->getPointer();
4223 std::vector<int> newc;
4224 for(int j=0;j<nbOf2DCells;j++)
4226 AppendExtrudedCell(conn+connI[j],conn+connI[j+1],nbOfNodesOf1Lev,isQuad,newc);
4227 *newConnIPtr++=(int)newc.size();
4229 newConn->alloc((int)(newc.size())*nbOf1DCells,1);
4230 int *newConnPtr=newConn->getPointer();
4231 int deltaPerLev=isQuad?2*nbOfNodesOf1Lev:nbOfNodesOf1Lev;
4232 newConnIPtr=newConnI->getPointer();
4233 for(int iz=0;iz<nbOf1DCells;iz++)
4236 std::transform(newConnIPtr+1,newConnIPtr+1+nbOf2DCells,newConnIPtr+1+iz*nbOf2DCells,std::bind2nd(std::plus<int>(),newConnIPtr[iz*nbOf2DCells]));
4237 for(std::vector<int>::const_iterator iter=newc.begin();iter!=newc.end();iter++,newConnPtr++)
4239 int icell=(int)(iter-newc.begin());
4240 if(std::find(newConnIPtr,newConnIPtr+nbOf2DCells,icell)==newConnIPtr+nbOf2DCells)
4243 *newConnPtr=(*iter)+iz*deltaPerLev;
4248 *newConnPtr=(*iter);
4251 ret->setConnectivity(newConn,newConnI,true);
4253 newConnI->decrRef();
4254 ret->setCoords(getCoords());
4259 * This method returns if 'this' is constituted by only quadratic cells.
4261 bool MEDCouplingUMesh::isFullyQuadratic() const
4263 checkFullyDefined();
4265 int nbOfCells=getNumberOfCells();
4266 for(int i=0;i<nbOfCells && ret;i++)
4268 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4269 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4270 ret=cm.isQuadratic();
4276 * This method returns if there is at least one quadratic cell.
4278 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
4280 checkFullyDefined();
4282 int nbOfCells=getNumberOfCells();
4283 for(int i=0;i<nbOfCells && !ret;i++)
4285 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4286 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4287 ret=cm.isQuadratic();
4293 * This method convert quadratic cells to linear cells if any was found.
4294 * If no such cells exists 'this' remains unchanged.
4296 void MEDCouplingUMesh::convertQuadraticCellsToLinear() throw(INTERP_KERNEL::Exception)
4298 checkFullyDefined();
4299 int nbOfCells=getNumberOfCells();
4301 for(int i=0;i<nbOfCells;i++)
4303 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4304 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4305 if(cm.isQuadratic())
4307 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4308 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4309 delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
4314 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newConn=DataArrayInt::New();
4315 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newConnI=DataArrayInt::New();
4316 newConn->alloc(getMeshLength()-delta,1);
4317 newConnI->alloc(nbOfCells+1,1);
4318 const int *icptr=_nodal_connec->getConstPointer();
4319 const int *iciptr=_nodal_connec_index->getConstPointer();
4320 int *ocptr=newConn->getPointer();
4321 int *ociptr=newConnI->getPointer();
4324 for(int i=0;i<nbOfCells;i++,ociptr++)
4326 INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4327 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4328 if(!cm.isQuadratic())
4330 _types.insert(type);
4331 ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
4332 ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
4336 INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4337 _types.insert(typel);
4338 const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4339 int newNbOfNodes=cml.getNumberOfNodes();
4340 *ocptr++=(int)typel;
4341 ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
4342 ociptr[1]=ociptr[0]+newNbOfNodes+1;
4345 setConnectivity(newConn,newConnI,false);
4349 * This method tessallates 'this' so that the number of cells remains the same.
4350 * This method works only for meshes with spaceDim equal to 2 and meshDim equal to 2.
4351 * If no cells are quadratic in 'this' (INTERP_KERNEL::NORM_QUAD8, INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ) this method will remain unchanged.
4353 * \b WARNING this method can lead to a uge amount of nodes if eps is very low.
4354 * @param eps specifies the maximal angle (in radian) between 2 subedges of polylinized edge constituting the input polygon.
4356 void MEDCouplingUMesh::tessellate2D(double eps) throw(INTERP_KERNEL::Exception)
4358 checkFullyDefined();
4359 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4360 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D works on umeshes with meshdim equal to 2 and spaceDim equal to 2 too!");
4361 double epsa=fabs(eps);
4362 if(epsa<std::numeric_limits<double>::min())
4363 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DCurve : epsilon is null ! Please specify a higher epsilon. If too tiny it can lead to a huge amount of nodes and memory !");
4364 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> desc1=DataArrayInt::New();
4365 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> descIndx1=DataArrayInt::New();
4366 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revDesc1=DataArrayInt::New();
4367 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revDescIndx1=DataArrayInt::New();
4368 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> mDesc=buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1);
4369 revDesc1=0; revDescIndx1=0;
4370 mDesc->tessellate2DCurve(eps);
4371 subDivide2DMesh(mDesc->_nodal_connec->getConstPointer(),mDesc->_nodal_connec_index->getConstPointer(),desc1->getConstPointer(),descIndx1->getConstPointer());
4372 setCoords(mDesc->getCoords());
4376 * This method tessallates 'this' so that the number of cells remains the same.
4377 * This method works only for meshes with spaceDim equal to 2 and meshDim equal to 1.
4378 * If no cells are quadratic in 'this' (INTERP_KERNEL::NORM_QUAD8, INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ) this method will remain unchanged.
4380 * \b WARNING this method can lead to a uge amount of nodes if eps is very low.
4381 * @param eps specifies the maximal angle (in radian) between 2 subedges of polylinized edge constituting the input polygon.
4383 void MEDCouplingUMesh::tessellate2DCurve(double eps) throw(INTERP_KERNEL::Exception)
4385 checkFullyDefined();
4386 if(getMeshDimension()!=1 || getSpaceDimension()!=2)
4387 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DCurve works on umeshes with meshdim equal to 1 and spaceDim equal to 2 too!");
4388 double epsa=fabs(eps);
4389 if(epsa<std::numeric_limits<double>::min())
4390 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DCurve : epsilon is null ! Please specify a higher epsilon. If too tiny it can lead to a huge amount of nodes and memory !");
4391 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=1.e-10;
4392 int nbCells=getNumberOfCells();
4393 int nbNodes=getNumberOfNodes();
4394 const int *conn=_nodal_connec->getConstPointer();
4395 const int *connI=_nodal_connec_index->getConstPointer();
4396 const double *coords=_coords->getConstPointer();
4397 std::vector<double> addCoo;
4398 std::vector<int> newConn;
4399 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newConnI=DataArrayInt::New();
4400 newConnI->alloc(nbCells+1,1);
4401 int *newConnIPtr=newConnI->getPointer();
4404 INTERP_KERNEL::Node *tmp2[3];
4405 std::set<INTERP_KERNEL::NormalizedCellType> types;
4406 for(int i=0;i<nbCells;i++,newConnIPtr++)
4408 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4409 if(cm.isQuadratic())
4410 {//assert(connI[i+1]-connI[i]-1==3)
4411 tmp1[0]=conn[connI[i]+1+0]; tmp1[1]=conn[connI[i]+1+1]; tmp1[2]=conn[connI[i]+1+2];
4412 tmp2[0]=new INTERP_KERNEL::Node(coords[2*tmp1[0]],coords[2*tmp1[0]+1]);
4413 tmp2[1]=new INTERP_KERNEL::Node(coords[2*tmp1[1]],coords[2*tmp1[1]+1]);
4414 tmp2[2]=new INTERP_KERNEL::Node(coords[2*tmp1[2]],coords[2*tmp1[2]+1]);
4415 INTERP_KERNEL::EdgeArcCircle *eac=INTERP_KERNEL::EdgeArcCircle::BuildFromNodes(tmp2[0],tmp2[2],tmp2[1]);
4418 eac->tesselate(tmp1,nbNodes,epsa,newConn,addCoo);
4419 types.insert((INTERP_KERNEL::NormalizedCellType)newConn[newConnIPtr[0]]);
4421 newConnIPtr[1]=(int)newConn.size();
4425 types.insert(INTERP_KERNEL::NORM_SEG2);
4426 newConn.push_back(INTERP_KERNEL::NORM_SEG2);
4427 newConn.insert(newConn.end(),conn+connI[i]+1,conn+connI[i]+3);
4428 newConnIPtr[1]=newConnIPtr[0]+3;
4433 types.insert((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4434 newConn.insert(newConn.end(),conn+connI[i],conn+connI[i+1]);
4435 newConnIPtr[1]=newConnIPtr[0]+3;
4438 if(addCoo.empty() && ((int)newConn.size())==_nodal_connec->getNumberOfTuples())//nothing happens during tasselation : no update needed
4441 DataArrayInt::SetArrayIn(newConnI,_nodal_connec_index);
4442 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newConnArr=DataArrayInt::New();
4443 newConnArr->alloc((int)newConn.size(),1);
4444 std::copy(newConn.begin(),newConn.end(),newConnArr->getPointer());
4445 DataArrayInt::SetArrayIn(newConnArr,_nodal_connec);
4446 MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> newCoords=DataArrayDouble::New();
4447 newCoords->alloc(nbNodes+((int)addCoo.size())/2,2);
4448 double *work=std::copy(_coords->begin(),_coords->end(),newCoords->getPointer());
4449 std::copy(addCoo.begin(),addCoo.end(),work);
4450 DataArrayDouble::SetArrayIn(newCoords,_coords);
4455 * This methods modify this by converting each cells into simplex cell, that is too say triangle for meshdim==2 or tetra for meshdim==3.
4456 * This cut into simplex is performed following the parameter 'policy'. This method so typically increases the number of cells of this.
4457 * This method returns new2old array that specifies a each cell of 'this' after the call what was its id it comes.
4459 * The semantic of 'policy' parameter :
4460 * - 1 only QUAD4. For QUAD4 the cut is done along 0-2 diagonal for QUAD4
4461 * - 2 only QUAD4. For QUAD4 the cut is done along 1-3 diagonal for QUAD4
4463 DataArrayInt *MEDCouplingUMesh::simplexize(int policy) throw(INTERP_KERNEL::Exception)
4468 return simplexizePol0();
4470 return simplexizePol1();
4472 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexize : unrecognized policy ! Must be 0 or 1 !");
4476 bool MEDCouplingUMesh::areOnlySimplexCells() const throw(INTERP_KERNEL::Exception)
4478 checkFullyDefined();
4479 if(getMeshDimension()<1)
4480 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim >= 1 !");
4481 int nbCells=getNumberOfCells();
4482 const int *conn=_nodal_connec->getConstPointer();
4483 const int *connI=_nodal_connec_index->getConstPointer();
4484 for(int i=0;i<nbCells;i++)
4486 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4494 * This method implements policy 0 of virtual method ParaMEDMEM::MEDCouplingUMesh::simplexize.
4496 DataArrayInt *MEDCouplingUMesh::simplexizePol0() throw(INTERP_KERNEL::Exception)
4498 if(getMeshDimension()!=2)
4499 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePol0 : this policy is only available for mesh with meshdim == 2 !");
4500 int nbOfCells=getNumberOfCells();
4501 DataArrayInt *ret=DataArrayInt::New();
4502 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_QUAD4);
4503 ret->alloc(nbOfCells+nbOfCutCells,1);
4509 int *retPt=ret->getPointer();
4510 DataArrayInt *newConn=DataArrayInt::New();
4511 DataArrayInt *newConnI=DataArrayInt::New();
4512 newConnI->alloc(nbOfCells+nbOfCutCells+1,1);
4513 newConn->alloc(getMeshLength()+3*nbOfCutCells,1);
4514 int *pt=newConn->getPointer();
4515 int *ptI=newConnI->getPointer();
4517 const int *oldc=_nodal_connec->getConstPointer();
4518 const int *ci=_nodal_connec_index->getConstPointer();
4519 for(int i=0;i<nbOfCells;i++,ci++)
4521 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_QUAD4)
4523 const int tmp[8]={(int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+2],oldc[ci[0]+3],
4524 (int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+3],oldc[ci[0]+4]};
4525 pt=std::copy(tmp,tmp+8,pt);
4534 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
4535 ptI[1]=ptI[0]+ci[1]-ci[0];
4540 _nodal_connec->decrRef();
4541 _nodal_connec=newConn;
4542 _nodal_connec_index->decrRef();
4543 _nodal_connec_index=newConnI;
4550 * This method implements policy 1 of virtual method ParaMEDMEM::MEDCouplingUMesh::simplexize.
4552 DataArrayInt *MEDCouplingUMesh::simplexizePol1() throw(INTERP_KERNEL::Exception)
4554 if(getMeshDimension()!=2)
4555 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePol0 : this policy is only available for mesh with meshdim == 2 !");
4556 int nbOfCells=getNumberOfCells();
4557 DataArrayInt *ret=DataArrayInt::New();
4558 int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_QUAD4);
4559 ret->alloc(nbOfCells+nbOfCutCells,1);
4565 int *retPt=ret->getPointer();
4566 DataArrayInt *newConn=DataArrayInt::New();
4567 DataArrayInt *newConnI=DataArrayInt::New();
4568 newConnI->alloc(nbOfCells+nbOfCutCells+1,1);
4569 newConn->alloc(getMeshLength()+3*nbOfCutCells,1);
4570 int *pt=newConn->getPointer();
4571 int *ptI=newConnI->getPointer();
4573 const int *oldc=_nodal_connec->getConstPointer();
4574 const int *ci=_nodal_connec_index->getConstPointer();
4575 for(int i=0;i<nbOfCells;i++,ci++)
4577 if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_QUAD4)
4579 const int tmp[8]={(int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+2],oldc[ci[0]+4],
4580 (int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+2],oldc[ci[0]+3],oldc[ci[0]+4]};
4581 pt=std::copy(tmp,tmp+8,pt);
4590 pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
4591 ptI[1]=ptI[0]+ci[1]-ci[0];
4596 _nodal_connec->decrRef();
4597 _nodal_connec=newConn;
4598 _nodal_connec_index->decrRef();
4599 _nodal_connec_index=newConnI;
4606 * This private method is used to subdivide edges of a mesh with meshdim==2. If 'this' has no a meshdim equal to 2 an exception will be thrown.
4607 * This method completly ignore coordinates.
4608 * @param nodeSubdived is the nodal connectivity of subdivision of edges
4609 * @param nodeIndxSubdived is the nodal connectivity index of subdivision of edges
4610 * @param desc is descending connectivity in format specified in MEDCouplingUMesh::buildDescendingConnectivity2
4611 * @param descIndex is descending connectivity index in format specified in MEDCouplingUMesh::buildDescendingConnectivity2
4613 void MEDCouplingUMesh::subDivide2DMesh(const int *nodeSubdived, const int *nodeIndxSubdived, const int *desc, const int *descIndex) throw(INTERP_KERNEL::Exception)
4615 checkFullyDefined();
4616 if(getMeshDimension()!=2)
4617 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::subDivide2DMesh : works only on umesh with meshdim==2 !");
4618 int nbOfCells=getNumberOfCells();
4619 int *connI=_nodal_connec_index->getPointer();
4621 for(int i=0;i<nbOfCells;i++,connI++)
4623 int offset=descIndex[i];
4624 int nbOfEdges=descIndex[i+1]-offset;
4626 bool ddirect=desc[offset+nbOfEdges-1]>0;
4627 int eedgeId=std::abs(desc[offset+nbOfEdges-1])-1;
4628 int ref=ddirect?nodeSubdived[nodeIndxSubdived[eedgeId+1]-1]:nodeSubdived[nodeIndxSubdived[eedgeId]+1];
4629 for(int j=0;j<nbOfEdges;j++)
4631 bool direct=desc[offset+j]>0;
4632 int edgeId=std::abs(desc[offset+j])-1;
4633 if(!INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodeSubdived[nodeIndxSubdived[edgeId]]).isQuadratic())
4635 int id1=nodeSubdived[nodeIndxSubdived[edgeId]+1];
4636 int id2=nodeSubdived[nodeIndxSubdived[edgeId+1]-1];
4637 int ref2=direct?id1:id2;
4640 int nbOfSubNodes=nodeIndxSubdived[edgeId+1]-nodeIndxSubdived[edgeId]-1;
4641 newConnLgth+=nbOfSubNodes-1;
4646 std::ostringstream oss; oss << "MEDCouplingUMesh::subDivide2DMesh : On polygon #" << i << " edgeid #" << j << " subedges mismatch : end subedge k!=start subedge k+1 !";
4647 throw INTERP_KERNEL::Exception(oss.str().c_str());
4652 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::subDivide2DMesh : this method only subdivides into linear edges !");
4655 newConnLgth++;//+1 is for cell type
4656 connI[1]=newConnLgth;
4659 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newConn=DataArrayInt::New();
4660 newConn->alloc(newConnLgth,1);
4661 int *work=newConn->getPointer();
4662 for(int i=0;i<nbOfCells;i++)
4664 *work++=INTERP_KERNEL::NORM_POLYGON;
4665 int offset=descIndex[i];
4666 int nbOfEdges=descIndex[i+1]-offset;
4667 for(int j=0;j<nbOfEdges;j++)
4669 bool direct=desc[offset+j]>0;
4670 int edgeId=std::abs(desc[offset+j])-1;
4672 work=std::copy(nodeSubdived+nodeIndxSubdived[edgeId]+1,nodeSubdived+nodeIndxSubdived[edgeId+1]-1,work);
4675 int nbOfSubNodes=nodeIndxSubdived[edgeId+1]-nodeIndxSubdived[edgeId]-1;
4676 std::reverse_iterator<const int *> it(nodeSubdived+nodeIndxSubdived[edgeId+1]);
4677 work=std::copy(it,it+nbOfSubNodes-1,work);
4681 DataArrayInt::SetArrayIn(newConn,_nodal_connec);
4684 _types.insert(INTERP_KERNEL::NORM_POLYGON);
4688 * This method converts all degenerated cells to simpler cells. For example a NORM_QUAD4 cell consituted from 2 same node id in its
4689 * nodal connectivity will be transform to a NORM_TRI3 cell.
4690 * This method works \b only \b on \b linear cells.
4691 * This method works on nodes ids, that is to say a call to ParaMEDMEM::MEDCouplingUMesh::mergeNodes
4692 * method could be usefull before calling this method in case of presence of several pair of nodes located on same position.
4693 * This method throws an exception if 'this' is not fully defined (connectivity).
4694 * This method throws an exception too if a "too" degenerated cell is detected. For example a NORM_TRI3 with 3 times the same node id.
4696 void MEDCouplingUMesh::convertDegeneratedCells() throw(INTERP_KERNEL::Exception)
4698 checkFullyDefined();
4699 if(getMeshDimension()<=1)
4700 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4701 int nbOfCells=getNumberOfCells();
4704 int initMeshLgth=getMeshLength();
4705 int *conn=_nodal_connec->getPointer();
4706 int *index=_nodal_connec_index->getPointer();
4710 for(int i=0;i<nbOfCells;i++)
4712 lgthOfCurCell=index[i+1]-posOfCurCell;
4713 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4715 INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4716 conn+newPos+1,newLgth);
4717 conn[newPos]=newType;
4719 posOfCurCell=index[i+1];
4722 if(newPos!=initMeshLgth)
4723 _nodal_connec->reAlloc(newPos);
4728 * This method checks that all or only polygons (depending 'polyOnly' parameter) 2D cells are correctly oriented relative to 'vec' vector.
4729 * The 'vec' vector has to have a non nul norm.
4730 * If not 'cells' parameter will be appended with cellIds of incorrect cells.
4731 * @throw when 'this' is not a mesh with meshdim==2 and spacedim==3
4733 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<int>& cells) const throw(INTERP_KERNEL::Exception)
4735 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4736 throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
4737 int nbOfCells=getNumberOfCells();
4738 const int *conn=_nodal_connec->getConstPointer();
4739 const int *connI=_nodal_connec_index->getConstPointer();
4740 const double *coordsPtr=_coords->getConstPointer();
4741 for(int i=0;i<nbOfCells;i++)
4743 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4744 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4746 bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
4747 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4754 * This method orient correctly (if needed) all or only polygons (depending 'polyOnly' parameter) 2D cells are correctly oriented relative to 'vec' vector.
4755 * The 'vec' vector has to have a non nul norm.
4756 * @throw when 'this' is not a mesh with meshdim==2 and spacedim==3
4758 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly) throw(INTERP_KERNEL::Exception)
4760 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4761 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
4762 int nbOfCells=getNumberOfCells();
4763 int *conn=_nodal_connec->getPointer();
4764 const int *connI=_nodal_connec_index->getConstPointer();
4765 const double *coordsPtr=_coords->getConstPointer();
4766 bool isModified=false;
4767 for(int i=0;i<nbOfCells;i++)
4769 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4770 if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4772 bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
4773 if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4776 std::vector<int> tmp(connI[i+1]-connI[i]-2);
4777 std::copy(conn+connI[i]+2,conn+connI[i+1],tmp.rbegin());
4778 std::copy(tmp.begin(),tmp.end(),conn+connI[i]+2);
4783 _nodal_connec->declareAsNew();
4788 * This method checks that all polyhedrons cells have correctly oriented faces.
4789 * If not, 'cells' parameter will be appended with cellIds of incorrect cells.
4790 * @throw when 'this' is not a mesh with meshdim==3 and spacedim==3
4792 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<int>& cells) const throw(INTERP_KERNEL::Exception)
4794 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4795 throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
4796 int nbOfCells=getNumberOfCells();
4797 const int *conn=_nodal_connec->getConstPointer();
4798 const int *connI=_nodal_connec_index->getConstPointer();
4799 const double *coordsPtr=_coords->getConstPointer();
4800 for(int i=0;i<nbOfCells;i++)
4802 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4803 if(type==INTERP_KERNEL::NORM_POLYHED)
4805 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4812 * This method tries to orient correctly polhedrons cells.
4813 * @throw when 'this' is not a mesh with meshdim==3 and spacedim==3. An exception is also thrown when the attempt of reparation fails.
4815 void MEDCouplingUMesh::orientCorrectlyPolyhedrons() throw(INTERP_KERNEL::Exception)
4817 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4818 throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
4819 int nbOfCells=getNumberOfCells();
4820 int *conn=_nodal_connec->getPointer();
4821 const int *connI=_nodal_connec_index->getConstPointer();
4822 const double *coordsPtr=_coords->getConstPointer();
4823 bool isModified=false;
4824 for(int i=0;i<nbOfCells;i++)
4826 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4827 if(type==INTERP_KERNEL::NORM_POLYHED)
4828 if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4830 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
4835 _nodal_connec->declareAsNew();
4840 * This method has a sense for meshes with spaceDim==3 and meshDim==2.
4841 * If it is not the case an exception will be thrown.
4842 * This method is fast because the first cell of 'this' is used to compute the plane.
4843 * @param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
4844 * @param pos output of size at least 3 used to store a point owned of searched plane.
4846 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const throw(INTERP_KERNEL::Exception)
4848 if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4849 throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
4850 const int *conn=_nodal_connec->getConstPointer();
4851 const int *connI=_nodal_connec_index->getConstPointer();
4852 const double *coordsPtr=_coords->getConstPointer();
4853 INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
4854 std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
4858 * The returned newly created field has to be managed by the caller.
4859 * This method returns a field on cell with no time lying on 'this'. The meshdimension and spacedimension of this are expected to be both in [2,3]. If not an exception will be thrown.
4860 * This method for the moment only deals with NORM_TRI3, NORM_QUAD4 and NORM_TETRA4 geometric types.
4861 * If a cell has an another type an exception will be thrown.
4863 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const throw(INTERP_KERNEL::Exception)
4866 int spaceDim=getSpaceDimension();
4867 int meshDim=getMeshDimension();
4868 if(spaceDim!=2 && spaceDim!=3)
4869 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
4870 if(meshDim!=2 && meshDim!=3)
4871 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
4872 MEDCouplingAutoRefCountObjectPtr<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,NO_TIME);
4874 int nbOfCells=getNumberOfCells();
4875 DataArrayDouble *arr=DataArrayDouble::New();
4876 arr->alloc(nbOfCells,1);
4877 double *pt=arr->getPointer();
4878 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
4880 const int *conn=_nodal_connec->getConstPointer();
4881 const int *connI=_nodal_connec_index->getConstPointer();
4882 const double *coo=_coords->getConstPointer();
4884 for(int i=0;i<nbOfCells;i++,pt++)
4886 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
4889 case INTERP_KERNEL::NORM_TRI3:
4891 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
4892 *pt=INTERP_KERNEL::triEdgeRatio(tmp);
4895 case INTERP_KERNEL::NORM_QUAD4:
4897 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
4898 *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
4901 case INTERP_KERNEL::NORM_TETRA4:
4903 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
4904 *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
4908 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
4910 conn+=connI[i+1]-connI[i];
4912 ret->setName("EdgeRatio");
4918 * The returned newly created field has to be managed by the caller.
4919 * This method returns a field on cell with no time lying on 'this'. The meshdimension and spacedimension of this are expected to be both in [2,3]. If not an exception will be thrown.
4920 * This method for the moment only deals with NORM_TRI3, NORM_QUAD4 and NORM_TETRA4 geometric types.
4921 * If a cell has an another type an exception will be thrown.
4923 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const throw(INTERP_KERNEL::Exception)
4926 int spaceDim=getSpaceDimension();
4927 int meshDim=getMeshDimension();
4928 if(spaceDim!=2 && spaceDim!=3)
4929 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
4930 if(meshDim!=2 && meshDim!=3)
4931 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
4932 MEDCouplingAutoRefCountObjectPtr<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,NO_TIME);
4934 int nbOfCells=getNumberOfCells();
4935 DataArrayDouble *arr=DataArrayDouble::New();
4936 arr->alloc(nbOfCells,1);
4937 double *pt=arr->getPointer();
4938 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
4940 const int *conn=_nodal_connec->getConstPointer();
4941 const int *connI=_nodal_connec_index->getConstPointer();
4942 const double *coo=_coords->getConstPointer();
4944 for(int i=0;i<nbOfCells;i++,pt++)
4946 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
4949 case INTERP_KERNEL::NORM_TRI3:
4951 FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
4952 *pt=INTERP_KERNEL::triAspectRatio(tmp);
4955 case INTERP_KERNEL::NORM_QUAD4:
4957 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
4958 *pt=INTERP_KERNEL::quadAspectRatio(tmp);
4961 case INTERP_KERNEL::NORM_TETRA4:
4963 FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
4964 *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
4968 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
4970 conn+=connI[i+1]-connI[i];
4972 ret->setName("AspectRatio");
4978 * The returned newly created field has to be managed by the caller.
4979 * This method returns a field on cell with no time lying on 'this'. The meshdimension must be equal to 2 and the spacedimension must be equal to 3. If not an exception will be thrown.
4980 * This method for the moment only deals with NORM_QUAD4 geometric type.
4981 * If a cell has an another type an exception will be thrown.
4983 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const throw(INTERP_KERNEL::Exception)
4986 int spaceDim=getSpaceDimension();
4987 int meshDim=getMeshDimension();
4989 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
4991 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
4992 MEDCouplingAutoRefCountObjectPtr<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,NO_TIME);
4994 int nbOfCells=getNumberOfCells();
4995 DataArrayDouble *arr=DataArrayDouble::New();
4996 arr->alloc(nbOfCells,1);
4997 double *pt=arr->getPointer();
4998 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5000 const int *conn=_nodal_connec->getConstPointer();
5001 const int *connI=_nodal_connec_index->getConstPointer();
5002 const double *coo=_coords->getConstPointer();
5004 for(int i=0;i<nbOfCells;i++,pt++)
5006 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5009 case INTERP_KERNEL::NORM_QUAD4:
5011 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5012 *pt=INTERP_KERNEL::quadWarp(tmp);
5016 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
5018 conn+=connI[i+1]-connI[i];
5020 ret->setName("Warp");
5026 * The returned newly created field has to be managed by the caller.
5027 * This method returns a field on cell with no time lying on 'this'. The meshdimension must be equal to 2 and the spacedimension must be equal to 3. If not an exception will be thrown.
5028 * This method for the moment only deals with NORM_QUAD4 geometric type.
5029 * If a cell has an another type an exception will be thrown.
5031 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const throw(INTERP_KERNEL::Exception)
5034 int spaceDim=getSpaceDimension();
5035 int meshDim=getMeshDimension();
5037 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
5039 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
5040 MEDCouplingAutoRefCountObjectPtr<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,NO_TIME);
5042 int nbOfCells=getNumberOfCells();
5043 DataArrayDouble *arr=DataArrayDouble::New();
5044 arr->alloc(nbOfCells,1);
5045 double *pt=arr->getPointer();
5046 ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5048 const int *conn=_nodal_connec->getConstPointer();
5049 const int *connI=_nodal_connec_index->getConstPointer();
5050 const double *coo=_coords->getConstPointer();
5052 for(int i=0;i<nbOfCells;i++,pt++)
5054 INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5057 case INTERP_KERNEL::NORM_QUAD4:
5059 FillInCompact3DMode(3,4,conn+1,coo,tmp);
5060 *pt=INTERP_KERNEL::quadSkew(tmp);
5064 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
5066 conn+=connI[i+1]-connI[i];
5068 ret->setName("Skew");
5074 * This method aggregate the bbox of each cell and put it into bbox parameter.
5075 * @param bbox out parameter of size 2*spacedim*nbOfcells.
5077 void MEDCouplingUMesh::getBoundingBoxForBBTree(std::vector<double>& bbox) const
5079 int spaceDim=getSpaceDimension();
5080 int nbOfCells=getNumberOfCells();
5081 bbox.resize(2*nbOfCells*spaceDim);
5082 for(int i=0;i<nbOfCells*spaceDim;i++)
5084 bbox[2*i]=std::numeric_limits<double>::max();
5085 bbox[2*i+1]=-std::numeric_limits<double>::max();
5087 const double *coordsPtr=_coords->getConstPointer();
5088 const int *conn=_nodal_connec->getConstPointer();
5089 const int *connI=_nodal_connec_index->getConstPointer();
5090 for(int i=0;i<nbOfCells;i++)
5092 int offset=connI[i]+1;
5093 int nbOfNodesForCell=connI[i+1]-offset;
5094 for(int j=0;j<nbOfNodesForCell;j++)
5096 int nodeId=conn[offset+j];
5098 for(int k=0;k<spaceDim;k++)
5100 bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
5101 bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
5109 namespace ParaMEDMEMImpl
5114 ConnReader(const int *c, int val):_conn(c),_val(val) { }
5115 bool operator() (const int& pos) { return _conn[pos]!=_val; }
5124 ConnReader2(const int *c, int val):_conn(c),_val(val) { }
5125 bool operator() (const int& pos) { return _conn[pos]==_val; }
5135 * This method expects that 'this' is sorted by types. If not an exception will be thrown.
5136 * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
5137 * 'this' is composed in cell types.
5138 * The returned array is of size 3*n where n is the number of different types present in 'this'.
5139 * For every k in [0,n] ret[3*k+2]==0 because it has no sense here.
5140 * This parameter is kept only for compatibility with other methode listed above.
5142 std::vector<int> MEDCouplingUMesh::getDistributionOfTypes() const throw(INTERP_KERNEL::Exception)
5144 checkConnectivityFullyDefined();
5145 const int *conn=_nodal_connec->getConstPointer();
5146 const int *connI=_nodal_connec_index->getConstPointer();
5147 const int *work=connI;
5148 int nbOfCells=getNumberOfCells();
5149 std::size_t n=getAllTypes().size();
5150 std::vector<int> ret(3*n,0); //ret[3*k+2]==0 because it has no sense here
5151 std::set<INTERP_KERNEL::NormalizedCellType> types;
5152 for(std::size_t i=0;work!=connI+nbOfCells;i++)
5154 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
5155 if(types.find(typ)!=types.end())
5157 std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
5158 oss << " is not contiguous !";
5159 throw INTERP_KERNEL::Exception(oss.str().c_str());
5163 const int *work2=std::find_if(work+1,connI+nbOfCells,ParaMEDMEMImpl::ConnReader(conn,typ));
5164 ret[3*i+1]=(int)std::distance(work,work2);
5171 * This method is used to check that this has contiguous cell type in same order than described in 'code'.
5172 * only for types cell, type node is not managed.
5173 * Format of 'code' is the following. 'code' should be of size 3*n and non empty. If not an exception is thrown.
5174 * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
5175 * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
5176 * If 2 or more same geometric type is in 'code' and exception is thrown too.
5178 * This method firstly checks
5179 * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
5180 * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
5181 * an exception is thrown too.
5183 * If all geometric types in 'code' are exactly those in 'this' null pointer is returned.
5184 * If it exists a geometric type in 'this' \b not in 'code' \b no exception is thrown
5185 * and a DataArrayInt instance is returned that the user has the responsability to deallocate.
5187 DataArrayInt *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<int>& code, const std::vector<const DataArrayInt *>& idsPerType) const throw(INTERP_KERNEL::Exception)
5190 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
5191 std::size_t sz=code.size();
5194 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
5195 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5197 for(std::size_t i=0;i<n;i++)
5198 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
5200 types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
5202 if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
5203 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
5206 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
5207 if(idsPerType.empty())
5209 if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
5210 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
5211 if(types.size()==_types.size())
5214 DataArrayInt *ret=DataArrayInt::New();
5216 int *retPtr=ret->getPointer();
5217 const int *connI=_nodal_connec_index->getConstPointer();
5218 const int *conn=_nodal_connec->getConstPointer();
5219 int nbOfCells=getNumberOfCells();
5222 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
5224 i=std::find_if(i,connI+nbOfCells,ParaMEDMEMImpl::ConnReader2(conn,(int)(*it)));
5225 int offset=(int)std::distance(connI,i);
5226 if(code[3*kk+2]==-1)
5228 const int *j=std::find_if(i+1,connI+nbOfCells,ParaMEDMEMImpl::ConnReader(conn,(int)(*it)));
5229 std::size_t pos2=std::distance(i,j);
5230 for(std::size_t k=0;k<pos2;k++)
5231 *retPtr++=(int)k+offset;
5236 retPtr=std::transform(idsPerType[code[3*kk+2]]->getConstPointer(),idsPerType[code[3*kk+2]]->getConstPointer()+idsPerType[code[3*kk+2]]->getNbOfElems(),
5237 retPtr,std::bind2nd(std::plus<int>(),offset));
5244 * This method makes the hypothesis that \at this is sorted by type. If not an exception will be thrown.
5245 * 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.
5246 * 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.
5247 * This method has 1 input \a profile and 3 outputs \a code' \a idsInPflPerType and \a idsPerType.
5249 * @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.
5250 * @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,
5251 * \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
5252 * @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.
5253 * This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
5254 * @throw if \a profile has not exactly one component. It throws too, if \a profile contains some values not in [0,getNumberOfCells()) or if 'this' is not fully defined
5256 void MEDCouplingUMesh::splitProfilePerType(const DataArrayInt *profile, std::vector<int>& code, std::vector<DataArrayInt *>& idsInPflPerType, std::vector<DataArrayInt *>& idsPerType) const throw(INTERP_KERNEL::Exception)
5258 if(profile->getNumberOfComponents()!=1)
5259 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
5260 checkConnectivityFullyDefined();
5261 const int *conn=_nodal_connec->getConstPointer();
5262 const int *connI=_nodal_connec_index->getConstPointer();
5263 int nbOfCells=getNumberOfCells();
5264 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5265 std::vector<int> typeRangeVals(1);
5266 for(const int *i=connI;i!=connI+nbOfCells;)
5268 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5269 if(std::find(types.begin(),types.end(),curType)!=types.end())
5271 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
5273 types.push_back(curType);
5274 i=std::find_if(i+1,connI+nbOfCells,ParaMEDMEMImpl::ConnReader(conn,(int)curType));
5275 typeRangeVals.push_back((int)std::distance(connI,i));
5278 DataArrayInt *castArr=0,*rankInsideCast=0,*castsPresent=0;
5279 profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
5280 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp0=castArr;
5281 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp1=rankInsideCast;
5282 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp2=castsPresent;
5284 int nbOfCastsFinal=castsPresent->getNumberOfTuples();
5285 code.resize(3*nbOfCastsFinal);
5286 std::vector< MEDCouplingAutoRefCountObjectPtr<DataArrayInt> > idsInPflPerType2;
5287 std::vector< MEDCouplingAutoRefCountObjectPtr<DataArrayInt> > idsPerType2;
5288 for(int i=0;i<nbOfCastsFinal;i++)
5290 int castId=castsPresent->getIJ(i,0);
5291 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp3=castArr->getIdsEqual(castId);
5292 idsInPflPerType2.push_back(tmp3);
5293 code[3*i]=(int)types[castId];
5294 code[3*i+1]=tmp3->getNumberOfTuples();
5295 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp4=rankInsideCast->selectByTupleId(tmp3->getConstPointer(),tmp3->getConstPointer()+tmp3->getNumberOfTuples());
5296 if(tmp4->getNumberOfTuples()!=typeRangeVals[castId+1]-typeRangeVals[castId] || !tmp4->isIdentity())
5298 tmp4->copyStringInfoFrom(*profile);
5299 idsPerType2.push_back(tmp4);
5300 code[3*i+2]=(int)idsPerType2.size()-1;
5307 std::size_t sz2=idsInPflPerType2.size();
5308 idsInPflPerType.resize(sz2);
5309 for(std::size_t i=0;i<sz2;i++)
5311 DataArrayInt *locDa=idsInPflPerType2[i];
5313 idsInPflPerType[i]=locDa;
5315 std::size_t sz=idsPerType2.size();
5316 idsPerType.resize(sz);
5317 for(std::size_t i=0;i<sz;i++)
5319 DataArrayInt *locDa=idsPerType2[i];
5321 idsPerType[i]=locDa;
5326 * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
5327 * This method make the assumption that 'this' and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
5328 * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
5329 * This method returns 5+2 elements. 'desc', 'descIndx', 'revDesc', 'revDescIndx' and 'meshnM1' behaves exactly as ParaMEDMEM::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.
5331 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *&revDesc, DataArrayInt *&revDescIndx, DataArrayInt *& nM1LevMeshIds, DataArrayInt *&meshnM1Old2New) const throw(INTERP_KERNEL::Exception)
5333 checkFullyDefined();
5334 nM1LevMesh->checkFullyDefined();
5335 if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
5336 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
5337 if(_coords!=nM1LevMesh->getCoords())
5338 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
5339 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp0=DataArrayInt::New();
5340 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp1=DataArrayInt::New();
5341 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
5342 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret0=ret1->sortCellsInMEDFileFrmt();
5343 desc->transformWithIndArr(ret0->getConstPointer(),ret0->getConstPointer()+ret0->getNbOfElems());
5344 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
5345 tmp->setConnectivity(tmp0,tmp1);
5346 tmp->renumberCells(ret0->getConstPointer(),false);
5347 revDesc=tmp->getNodalConnectivity();
5348 revDescIndx=tmp->getNodalConnectivityIndex();
5349 DataArrayInt *ret=0;
5350 if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
5353 ret->getMaxValue(tmp2);
5355 std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
5356 throw INTERP_KERNEL::Exception(oss.str().c_str());
5361 revDescIndx->incrRef();
5364 meshnM1Old2New=ret0;
5369 * This method sorts cell in this so that cells are sorted by cell type specified by MEDMEM and so for MED file.
5370 * It avoids to deal with renum in MEDLoader so it is usefull for MED file R/W with multi types.
5371 * This method returns a newly allocated array old2New.
5372 * This method expects that connectivity of this is set. If not an exception will be thrown. Coordinates are not taken into account.
5374 DataArrayInt *MEDCouplingUMesh::sortCellsInMEDFileFrmt() throw(INTERP_KERNEL::Exception)
5376 checkConnectivityFullyDefined();
5377 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret=getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
5378 renumberCells(ret->getConstPointer(),false);
5384 * This methods checks that cells are sorted by their types.
5385 * This method makes asumption (no check) that connectivity is correctly set before calling.
5387 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
5389 checkFullyDefined();
5390 const int *conn=_nodal_connec->getConstPointer();
5391 const int *connI=_nodal_connec_index->getConstPointer();
5392 int nbOfCells=getNumberOfCells();
5393 std::set<INTERP_KERNEL::NormalizedCellType> types;
5394 for(const int *i=connI;i!=connI+nbOfCells;)
5396 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5397 if(types.find(curType)!=types.end())
5399 types.insert(curType);
5400 i=std::find_if(i+1,connI+nbOfCells,ParaMEDMEMImpl::ConnReader(conn,(int)curType));
5406 * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
5407 * that the order is specified in array defined by [orderBg,orderEnd).
5409 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
5411 checkFullyDefined();
5412 const int *conn=_nodal_connec->getConstPointer();
5413 const int *connI=_nodal_connec_index->getConstPointer();
5414 int nbOfCells=getNumberOfCells();
5416 for(const int *i=connI;i!=connI+nbOfCells;)
5418 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5419 int pos=(int)std::distance(orderBg,std::find(orderBg,orderEnd,curType));
5423 i=std::find_if(i+1,connI+nbOfCells,ParaMEDMEMImpl::ConnReader(conn,(int)curType));
5429 * This method returns 2 newly allocated DataArrayInt instances. The first is an array of size 'this->getNumberOfCells()' with one component,
5430 * 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
5431 * 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'.
5433 DataArrayInt *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayInt *&nbPerType) const throw(INTERP_KERNEL::Exception)
5435 checkConnectivityFullyDefined();
5436 int nbOfCells=getNumberOfCells();
5437 const int *conn=_nodal_connec->getConstPointer();
5438 const int *connI=_nodal_connec_index->getConstPointer();
5439 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmpa=DataArrayInt::New();
5440 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmpb=DataArrayInt::New();
5441 tmpa->alloc(nbOfCells,1);
5442 tmpb->alloc((int)std::distance(orderBg,orderEnd),1);
5443 tmpb->fillWithZero();
5444 int *tmp=tmpa->getPointer();
5445 int *tmp2=tmpb->getPointer();
5446 for(const int *i=connI;i!=connI+nbOfCells;i++)
5448 const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
5451 int pos=(int)std::distance(orderBg,where);
5453 tmp[std::distance(connI,i)]=pos;
5457 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
5458 std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
5459 oss << " has a type " << cm.getRepr() << " not in input array of type !";
5460 throw INTERP_KERNEL::Exception(oss.str().c_str());
5470 * This method is similar to method MEDCouplingUMesh::rearrange2ConsecutiveCellTypes except that the type order is specfied by [orderBg,orderEnd) (as MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method) and that this method is \b const and performs \b NO permutation in 'this'.
5471 * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
5472 * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
5473 * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
5475 DataArrayInt *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const throw(INTERP_KERNEL::Exception)
5477 DataArrayInt *nbPerType=0;
5478 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
5479 nbPerType->decrRef();
5480 return tmpa->buildPermArrPerLevel();
5484 * This method reorganize the cells of 'this' so that the cells with same geometric types are put together.
5485 * The number of cells remains unchanged after the call of this method.
5486 * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
5487 * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
5489 * @return the array giving the correspondance old to new.
5491 DataArrayInt *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
5493 checkFullyDefined();
5495 const int *conn=_nodal_connec->getConstPointer();
5496 const int *connI=_nodal_connec_index->getConstPointer();
5497 int nbOfCells=getNumberOfCells();
5498 std::vector<INTERP_KERNEL::NormalizedCellType> types;
5499 for(const int *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
5500 if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
5502 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5503 types.push_back(curType);
5504 for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
5506 DataArrayInt *ret=DataArrayInt::New();
5507 ret->alloc(nbOfCells,1);
5508 int *retPtr=ret->getPointer();
5509 std::fill(retPtr,retPtr+nbOfCells,-1);
5511 for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
5513 for(const int *i=connI;i!=connI+nbOfCells;i++)
5514 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
5515 retPtr[std::distance(connI,i)]=newCellId++;
5517 renumberCells(retPtr,false);
5522 * This method splits 'this' into as mush as untructured meshes that consecutive set of same type cells.
5523 * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
5524 * This method makes asumption that connectivity is correctly set before calling.
5526 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
5528 checkFullyDefined();
5529 const int *conn=_nodal_connec->getConstPointer();
5530 const int *connI=_nodal_connec_index->getConstPointer();
5531 int nbOfCells=getNumberOfCells();
5532 std::vector<MEDCouplingUMesh *> ret;
5533 for(const int *i=connI;i!=connI+nbOfCells;)
5535 INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5536 int beginCellId=(int)std::distance(connI,i);
5537 i=std::find_if(i+1,connI+nbOfCells,ParaMEDMEMImpl::ConnReader(conn,(int)curType));
5538 int endCellId=(int)std::distance(connI,i);
5539 int sz=endCellId-beginCellId;
5540 int *cells=new int[sz];
5541 for(int j=0;j<sz;j++)
5542 cells[j]=beginCellId+j;
5543 MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
5551 * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
5552 * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
5553 * This method is particulary useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
5554 * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
5555 * are not used here to avoid the build of big permutation array.
5557 * \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
5558 * those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
5559 * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayInt instance whose number of tuples is equal to the number of chunks of same geotype
5560 * in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
5561 * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayInt instance having the same size than \b szOfCellGrpOfSameType. This
5562 * output array gives for each chunck of same type the corresponding mesh id in \b ms.
5563 * \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
5564 * is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
5566 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
5567 DataArrayInt *&szOfCellGrpOfSameType,
5568 DataArrayInt *&idInMsOfCellGrpOfSameType) throw(INTERP_KERNEL::Exception)
5570 std::vector<const MEDCouplingUMesh *> ms2;
5571 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
5574 (*it)->checkConnectivityFullyDefined();
5578 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
5579 const DataArrayDouble *refCoo=ms2[0]->getCoords();
5580 int meshDim=ms2[0]->getMeshDimension();
5581 std::vector<const MEDCouplingUMesh *> m1ssm;
5582 std::vector< MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> > m1ssmAuto;
5584 std::vector<const MEDCouplingUMesh *> m1ssmSingle;
5585 std::vector< MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> > m1ssmSingleAuto;
5587 std::vector<int> ret1Data;
5588 std::vector<int> ret2Data;
5589 for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
5591 if(meshDim!=(*it)->getMeshDimension())
5592 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
5593 if(refCoo!=(*it)->getCoords())
5594 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
5595 std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
5596 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
5597 std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> > >(m1ssmAuto));
5598 for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
5600 MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
5601 m1ssmSingleAuto.push_back(singleCell);
5602 m1ssmSingle.push_back(singleCell);
5603 ret1Data.push_back((*it2)->getNumberOfCells()); ret2Data.push_back(rk);
5606 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret1=DataArrayInt::New(); ret1->alloc((int)m1ssmSingle.size(),1); std::copy(ret1Data.begin(),ret1Data.end(),ret1->getPointer());
5607 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret2=DataArrayInt::New(); ret2->alloc((int)m1ssmSingle.size(),1); std::copy(ret2Data.begin(),ret2Data.end(),ret2->getPointer());
5608 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
5609 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
5610 std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
5611 for(std::size_t i=0;i<m1ssm.size();i++)
5612 m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
5613 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
5614 szOfCellGrpOfSameType=ret1->renumber(renum->getConstPointer());
5615 idInMsOfCellGrpOfSameType=ret2->renumber(renum->getConstPointer());
5621 * This method returns a newly created DataArrayInt instance.
5622 * This method retrieves cell ids in [begin,end) that have the type 'type'.
5624 DataArrayInt *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const int *begin, const int *end) const throw(INTERP_KERNEL::Exception)
5626 checkFullyDefined();
5628 const int *conn=_nodal_connec->getConstPointer();
5629 const int *connIndex=_nodal_connec_index->getConstPointer();
5630 for(const int *w=begin;w!=end;w++)
5631 if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
5633 DataArrayInt *ret=DataArrayInt::New();
5634 ret->alloc((int)r.size(),1);
5635 std::copy(r.begin(),r.end(),ret->getPointer());
5640 * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
5641 * are in [0:getNumberOfCells())
5643 DataArrayInt *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayInt *da) const throw(INTERP_KERNEL::Exception)
5645 checkFullyDefined();
5646 const int *conn=_nodal_connec->getConstPointer();
5647 const int *connI=_nodal_connec_index->getConstPointer();
5648 int nbOfCells=getNumberOfCells();
5649 std::set<INTERP_KERNEL::NormalizedCellType> types=getAllTypes();
5650 int *tmp=new int[nbOfCells];
5651 for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
5654 for(const int *i=connI;i!=connI+nbOfCells;i++)
5655 if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
5656 tmp[std::distance(connI,i)]=j++;
5658 DataArrayInt *ret=DataArrayInt::New();
5659 ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
5660 ret->copyStringInfoFrom(*da);
5661 int *retPtr=ret->getPointer();
5662 const int *daPtr=da->getConstPointer();
5663 int nbOfElems=da->getNbOfElems();
5664 for(int k=0;k<nbOfElems;k++)
5665 retPtr[k]=tmp[daPtr[k]];
5671 * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
5672 * This method \b works \b for mesh sorted by type.
5673 * cells whose ids is in 'idsPerGeoType' array.
5674 * This method conserves coords and name of mesh.
5676 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const int *idsPerGeoTypeBg, const int *idsPerGeoTypeEnd) const
5678 std::vector<int> code=getDistributionOfTypes();
5679 std::size_t nOfTypesInThis=code.size()/3;
5680 int sz=0,szOfType=0;
5681 for(std::size_t i=0;i<nOfTypesInThis;i++)
5686 szOfType=code[3*i+1];
5688 for(const int *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
5689 if(*work<0 || *work>=szOfType)
5691 std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
5692 oss << ". It should be in [0," << szOfType << ") !";
5693 throw INTERP_KERNEL::Exception(oss.str().c_str());
5695 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> idsTokeep=DataArrayInt::New(); idsTokeep->alloc(sz+(int)std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
5696 int *idsPtr=idsTokeep->getPointer();
5698 for(std::size_t i=0;i<nOfTypesInThis;i++)
5701 for(int j=0;j<code[3*i+1];j++)
5704 idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind2nd(std::plus<int>(),offset));
5705 offset+=code[3*i+1];
5707 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
5708 ret->copyTinyInfoFrom(this);
5714 * This method returns a vector of size 'this->getNumberOfCells()'.
5715 * This method retrieves for each cell in 'this' if it is linear (false) or quadratic(true).
5717 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const throw(INTERP_KERNEL::Exception)
5719 int ncell=getNumberOfCells();
5720 std::vector<bool> ret(ncell);
5721 const int *cI=getNodalConnectivityIndex()->getConstPointer();
5722 const int *c=getNodalConnectivity()->getConstPointer();
5723 for(int i=0;i<ncell;i++)
5725 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
5726 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5727 ret[i]=cm.isQuadratic();
5733 * Returns a newly created mesh (with ref count ==1) that contains merge of 'this' and 'other'.
5735 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
5737 if(other->getType()!=UNSTRUCTURED)
5738 throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
5739 const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
5740 return MergeUMeshes(this,otherC);
5744 * Returns an array with this->getNumberOfCells() tuples and this->getSpaceDimension() dimension.
5745 * The false barycenter is computed that is to say barycenter of a cell is computed using average on each
5746 * components of coordinates of the cell.
5748 DataArrayDouble *MEDCouplingUMesh::getBarycenterAndOwner() const
5750 DataArrayDouble *ret=DataArrayDouble::New();
5751 int spaceDim=getSpaceDimension();
5752 int nbOfCells=getNumberOfCells();
5753 ret->alloc(nbOfCells,spaceDim);
5754 ret->copyStringInfoFrom(*getCoords());
5755 double *ptToFill=ret->getPointer();
5756 double *tmp=new double[spaceDim];
5757 const int *nodal=_nodal_connec->getConstPointer();
5758 const int *nodalI=_nodal_connec_index->getConstPointer();
5759 const double *coor=_coords->getConstPointer();
5760 for(int i=0;i<nbOfCells;i++)
5762 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
5763 INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
5771 * This method is similar to MEDCouplingUMesh::getBarycenterAndOwner except that it works on subPart of 'this' without
5772 * building explicitely it. The input part is defined by an array [begin,end). All ids contained in this array should be less than this->getNumberOfCells().
5773 * No check of that will be done !
5775 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const int *begin, const int *end) const
5777 DataArrayDouble *ret=DataArrayDouble::New();
5778 int spaceDim=getSpaceDimension();
5779 int nbOfTuple=(int)std::distance(begin,end);
5780 ret->alloc(nbOfTuple,spaceDim);
5781 double *ptToFill=ret->getPointer();
5782 double *tmp=new double[spaceDim];
5783 const int *nodal=_nodal_connec->getConstPointer();
5784 const int *nodalI=_nodal_connec_index->getConstPointer();
5785 const double *coor=_coords->getConstPointer();
5786 for(const int *w=begin;w!=end;w++)
5788 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
5789 INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
5797 * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
5800 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da) throw(INTERP_KERNEL::Exception)
5803 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
5804 da->checkAllocated();
5805 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(da->getName().c_str(),0);
5807 int nbOfTuples=da->getNumberOfTuples();
5808 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> c=DataArrayInt::New();
5809 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cI=DataArrayInt::New();
5810 c->alloc(2*nbOfTuples,1);
5811 cI->alloc(nbOfTuples+1,1);
5812 int *cp=c->getPointer();
5813 int *cip=cI->getPointer();
5815 for(int i=0;i<nbOfTuples;i++)
5817 *cp++=INTERP_KERNEL::NORM_POINT1;
5821 ret->setConnectivity(c,cI,true);
5827 * Returns a newly created mesh (with ref count ==1) that contains merge of 'mesh1' and 'other'.
5828 * The coords of 'mesh2' are added at the end of coords of 'mesh1'.
5830 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2) throw(INTERP_KERNEL::Exception)
5832 std::vector<const MEDCouplingUMesh *> tmp(2);
5833 tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
5834 return MergeUMeshes(tmp);
5838 * This method returns in case of success a mesh constitued from union of all meshes in 'a'.
5839 * There should be \b no presence of null pointer into 'a'. If any an INTERP_KERNEL::Exception will be thrown.
5840 * The returned mesh will contain aggregation of nodes in 'a' (in the same order) and aggregation of
5841 * cells in meshes in 'a' (in the same order too).
5843 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(std::vector<const MEDCouplingUMesh *>& a) throw(INTERP_KERNEL::Exception)
5845 std::size_t sz=a.size();
5847 return MergeUMeshesLL(a);
5848 for(std::size_t ii=0;ii<sz;ii++)
5851 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
5852 throw INTERP_KERNEL::Exception(oss.str().c_str());
5854 std::vector< MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> > bb(sz);
5855 std::vector< const MEDCouplingUMesh * > aa(sz);
5857 for(std::size_t i=0;i<sz && spaceDim==-3;i++)
5859 const MEDCouplingUMesh *cur=a[i];
5860 const DataArrayDouble *coo=cur->getCoords();
5862 spaceDim=coo->getNumberOfComponents();
5865 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
5866 for(std::size_t i=0;i<sz;i++)
5868 bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
5871 return MergeUMeshesLL(aa);
5876 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesLL(std::vector<const MEDCouplingUMesh *>& a) throw(INTERP_KERNEL::Exception)
5879 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : input array must be NON EMPTY !");
5880 std::vector<const MEDCouplingUMesh *>::const_iterator it=a.begin();
5881 int meshDim=(*it)->getMeshDimension();
5882 int nbOfCells=(*it)->getNumberOfCells();
5883 int meshLgth=(*it++)->getMeshLength();
5884 for(;it!=a.end();it++)
5886 if(meshDim!=(*it)->getMeshDimension())
5887 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, MergeUMeshes impossible !");
5888 nbOfCells+=(*it)->getNumberOfCells();
5889 meshLgth+=(*it)->getMeshLength();
5891 std::vector<const MEDCouplingPointSet *> aps(a.size());
5892 std::copy(a.begin(),a.end(),aps.begin());
5893 DataArrayDouble *pts=MergeNodesArray(aps);
5894 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("merge",meshDim);
5895 ret->setCoords(pts);
5897 DataArrayInt *c=DataArrayInt::New();
5898 c->alloc(meshLgth,1);
5899 int *cPtr=c->getPointer();
5900 DataArrayInt *cI=DataArrayInt::New();
5901 cI->alloc(nbOfCells+1,1);
5902 int *cIPtr=cI->getPointer();
5906 for(it=a.begin();it!=a.end();it++)
5908 int curNbOfCell=(*it)->getNumberOfCells();
5909 const int *curCI=(*it)->_nodal_connec_index->getConstPointer();
5910 const int *curC=(*it)->_nodal_connec->getConstPointer();
5911 cIPtr=std::transform(curCI+1,curCI+curNbOfCell+1,cIPtr,std::bind2nd(std::plus<int>(),offset));
5912 for(int j=0;j<curNbOfCell;j++)
5914 const int *src=curC+curCI[j];
5916 for(;src!=curC+curCI[j+1];src++,cPtr++)
5924 offset+=curCI[curNbOfCell];
5925 offset2+=(*it)->getNumberOfNodes();
5928 ret->setConnectivity(c,cI,true);
5938 * Idem MergeUMeshes except that 'meshes' are expected to lyie on the same coords and 'meshes' have the same meshdim.
5939 * 'meshes' must be a non empty vector.
5941 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2) throw(INTERP_KERNEL::Exception)
5943 std::vector<const MEDCouplingUMesh *> tmp(2);
5944 tmp[0]=mesh1; tmp[1]=mesh2;
5945 return MergeUMeshesOnSameCoords(tmp);
5949 * Idem MergeUMeshes except that 'meshes' are expected to lyie on the same coords and 'meshes' have the same meshdim.
5950 * 'meshes' must be a non empty vector.
5952 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
5955 throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
5956 for(std::size_t ii=0;ii<meshes.size();ii++)
5959 std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
5960 throw INTERP_KERNEL::Exception(oss.str().c_str());
5962 const DataArrayDouble *coords=meshes.front()->getCoords();
5963 int meshDim=meshes.front()->getMeshDimension();
5964 std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
5966 int meshIndexLgth=0;
5967 for(;iter!=meshes.end();iter++)
5969 if(coords!=(*iter)->getCoords())
5970 throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
5971 if(meshDim!=(*iter)->getMeshDimension())
5972 throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
5973 meshLgth+=(*iter)->getMeshLength();
5974 meshIndexLgth+=(*iter)->getNumberOfCells();
5976 DataArrayInt *nodal=DataArrayInt::New();
5977 nodal->alloc(meshLgth,1);
5978 int *nodalPtr=nodal->getPointer();
5979 DataArrayInt *nodalIndex=DataArrayInt::New();
5980 nodalIndex->alloc(meshIndexLgth+1,1);
5981 int *nodalIndexPtr=nodalIndex->getPointer();
5983 for(iter=meshes.begin();iter!=meshes.end();iter++)
5985 const int *nod=(*iter)->getNodalConnectivity()->getConstPointer();
5986 const int *index=(*iter)->getNodalConnectivityIndex()->getConstPointer();
5987 int nbOfCells=(*iter)->getNumberOfCells();
5988 int meshLgth2=(*iter)->getMeshLength();
5989 nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
5990 if(iter!=meshes.begin())
5991 nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind2nd(std::plus<int>(),offset));
5993 nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
5996 MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
5997 ret->setName("merge");
5998 ret->setMeshDimension(meshDim);
5999 ret->setConnectivity(nodal,nodalIndex,true);
6000 ret->setCoords(coords);
6001 nodalIndex->decrRef();
6007 * This method fuses meshes 'meshes' and returns the fused mesh and the correspondances arrays for each mesh in 'meshes' in returned mesh.
6008 * If a same cell is detected in several meshes in 'meshes', this cell will appear only once in returned mesh (see ParaMEDMEM::MEDCouplingUMesh::zipConnectivityTraducer for more details)
6010 * @param meshes input non empty vector containing meshes having same coordiantes array and same mesh dimension.
6011 * @param compType see MEDCouplingUMesh::zipConnectivityTraducer
6012 * @param corr output vector with same size as 'meshes' parameter. corr[i] is the correspondance array of mesh meshes[i] in returned mesh.
6013 * The arrays contained in 'corr' parameter are returned with refcounter set to one.
6014 * To avoid memory leaks the caller have to deal with each instances of DataArrayInt contained in 'corr' parameter.
6015 * @return The mesh lying on the same coordinates than those in meshes. All cells in 'meshes' are in returned mesh with
6016 * @exception if meshes is a empty vector or meshes are not lying on same coordinates or meshes not have the same dimension.
6018 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayInt *>& corr)
6020 //All checks are delegated to MergeUMeshesOnSameCoords
6021 MEDCouplingUMesh *ret=MergeUMeshesOnSameCoords(meshes);
6022 DataArrayInt *o2n=ret->zipConnectivityTraducer(compType);
6023 corr.resize(meshes.size());
6024 std::size_t nbOfMeshes=meshes.size();
6026 const int *o2nPtr=o2n->getConstPointer();
6027 for(std::size_t i=0;i<nbOfMeshes;i++)
6029 DataArrayInt *tmp=DataArrayInt::New();
6030 int curNbOfCells=meshes[i]->getNumberOfCells();
6031 tmp->alloc(curNbOfCells,1);
6032 std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
6033 offset+=curNbOfCells;
6034 tmp->setName(meshes[i]->getName());
6042 * This method takes in input meshes \b meshes containing no null reference. If any an INTERP_KERNEL::Exception will be thrown.
6043 * \b meshes should have a good coherency (connectivity and coordinates well defined).
6044 * All mesh in \b meshes must have the same space dimension. If not an INTERP_KERNEL:Exception will be thrown.
6045 * But mesh in \b meshes \b can \b have \b different \b mesh \b dimension \b each \b other.
6047 * This method performs nothing if size of \b meshes is in [0,1].
6048 * This method is particulary usefull in MEDLoader context to build a \ref ParaMEDMEM::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
6049 * coordinates DataArrayDouble instance.
6051 * \param [in,out] meshes : vector containing no null instance of MEDCouplingUMesh that in case of success of this method will be modified.
6053 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes) throw(INTERP_KERNEL::Exception)
6055 std::size_t sz=meshes.size();
6058 std::vector< const DataArrayDouble * > coords(meshes.size());
6059 std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
6060 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
6064 (*it)->checkConnectivityFullyDefined();
6065 const DataArrayDouble *coo=(*it)->getCoords();
6070 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
6071 oss << " has no coordinate array defined !";
6072 throw INTERP_KERNEL::Exception(oss.str().c_str());
6077 std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
6078 oss << " is null !";
6079 throw INTERP_KERNEL::Exception(oss.str().c_str());
6082 MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
6083 std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
6084 int offset=(*it)->getNumberOfNodes();
6085 (*it++)->setCoords(res);
6086 for(;it!=meshes.end();it++)
6088 int oldNumberOfNodes=(*it)->getNumberOfNodes();
6089 (*it)->setCoords(res);
6090 (*it)->shiftNodeNumbersInConn(offset);
6091 offset+=oldNumberOfNodes;
6096 * This method takes in input meshes \b meshes containing no null reference. If any an INTERP_KERNEL::Exception will be thrown.
6097 * \b meshes should have a good coherency (connectivity and coordinates well defined).
6098 * All mesh in \b meshes must have the same space dimension. If not an INTERP_KERNEL:Exception will be thrown.
6099 * But mesh in \b meshes \b can \b have \b different \b mesh \b dimension \b each \b other.
6100 * If \b meshes share the same instance of DataArrayDouble as coordinates and that this instance is null, this method do nothing and no exception will be thrown.
6102 * This method performs nothing if size of \b meshes is empty.
6103 * This method is particulary usefull in MEDLoader context to perform a treatment of a MEDFileUMesh instance on different levels.
6104 * coordinates DataArrayDouble instance.
6106 * \param [in,out] meshes :vector containing no null instance of MEDCouplingUMesh sharing the same DataArrayDouble instance of coordinates, that in case of success of this method will be modified.
6107 * \param [in] eps is the distance in absolute (that should be positive !), so that 2 or more points within a distance of eps will be merged into a single point.
6109 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps) throw(INTERP_KERNEL::Exception)
6113 std::set<const DataArrayDouble *> s;
6114 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
6117 s.insert((*it)->getCoords());
6120 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 !";
6121 throw INTERP_KERNEL::Exception(oss.str().c_str());
6126 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 !";
6127 throw INTERP_KERNEL::Exception(oss.str().c_str());
6129 const DataArrayDouble *coo=*(s.begin());
6133 DataArrayInt *comm,*commI;
6134 coo->findCommonTuples(eps,-1,comm,commI);
6135 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp1(comm),tmp2(commI);
6136 int oldNbOfNodes=coo->getNumberOfTuples();
6138 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> o2n=DataArrayInt::BuildOld2NewArrayFromSurjectiveFormat2(oldNbOfNodes,comm,commI,newNbOfNodes);
6139 if(oldNbOfNodes==newNbOfNodes)
6141 MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->getConstPointer(),newNbOfNodes);
6142 for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
6144 (*it)->renumberNodesInConn(o2n->getConstPointer());
6145 (*it)->setCoords(newCoords);
6150 * This method takes in input a cell defined by its MEDcouplingUMesh connectivity [connBg,connEnd) and returns its extruded cell by inserting the result at the end of ret.
6151 * @param nbOfNodesPerLev in parameter that specifies the number of nodes of one slice of global dataset
6152 * @param isQuad specifies the policy of connectivity.
6153 * @ret in/out parameter in which the result will be append
6155 void MEDCouplingUMesh::AppendExtrudedCell(const int *connBg, const int *connEnd, int nbOfNodesPerLev, bool isQuad, std::vector<int>& ret)
6157 INTERP_KERNEL::NormalizedCellType flatType=(INTERP_KERNEL::NormalizedCellType)connBg[0];
6158 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(flatType);
6159 ret.push_back(cm.getExtrudedType());
6160 int deltaz=isQuad?2*nbOfNodesPerLev:nbOfNodesPerLev;
6163 case INTERP_KERNEL::NORM_POINT1:
6165 ret.push_back(connBg[1]);
6166 ret.push_back(connBg[1]+nbOfNodesPerLev);
6169 case INTERP_KERNEL::NORM_SEG2:
6171 int conn[4]={connBg[1],connBg[2],connBg[2]+deltaz,connBg[1]+deltaz};
6172 ret.insert(ret.end(),conn,conn+4);
6175 case INTERP_KERNEL::NORM_SEG3:
6177 int conn[8]={connBg[1],connBg[3],connBg[3]+deltaz,connBg[1]+deltaz,connBg[2],connBg[3]+nbOfNodesPerLev,connBg[2]+deltaz,connBg[1]+nbOfNodesPerLev};
6178 ret.insert(ret.end(),conn,conn+8);
6181 case INTERP_KERNEL::NORM_QUAD4:
6183 int conn[8]={connBg[1],connBg[2],connBg[3],connBg[4],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4]+deltaz};
6184 ret.insert(ret.end(),conn,conn+8);
6187 case INTERP_KERNEL::NORM_TRI3:
6189 int conn[6]={connBg[1],connBg[2],connBg[3],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz};
6190 ret.insert(ret.end(),conn,conn+6);
6193 case INTERP_KERNEL::NORM_TRI6:
6195 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,
6196 connBg[1]+nbOfNodesPerLev,connBg[2]+nbOfNodesPerLev,connBg[3]+nbOfNodesPerLev};
6197 ret.insert(ret.end(),conn,conn+15);
6200 case INTERP_KERNEL::NORM_QUAD8:
6203 connBg[1],connBg[2],connBg[3],connBg[4],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4]+deltaz,
6204 connBg[5],connBg[6],connBg[7],connBg[8],connBg[5]+deltaz,connBg[6]+deltaz,connBg[7]+deltaz,connBg[8]+deltaz,
6205 connBg[1]+nbOfNodesPerLev,connBg[2]+nbOfNodesPerLev,connBg[3]+nbOfNodesPerLev,connBg[4]+nbOfNodesPerLev
6207 ret.insert(ret.end(),conn,conn+20);
6210 case INTERP_KERNEL::NORM_POLYGON:
6212 std::back_insert_iterator< std::vector<int> > ii(ret);
6213 std::copy(connBg+1,connEnd,ii);
6215 std::reverse_iterator<const int *> rConnBg(connEnd);
6216 std::reverse_iterator<const int *> rConnEnd(connBg+1);
6217 std::transform(rConnBg,rConnEnd,ii,std::bind2nd(std::plus<int>(),deltaz));
6218 std::size_t nbOfRadFaces=std::distance(connBg+1,connEnd);
6219 for(std::size_t i=0;i<nbOfRadFaces;i++)
6222 int conn[4]={connBg[(i+1)%nbOfRadFaces+1],connBg[i+1],connBg[i+1]+deltaz,connBg[(i+1)%nbOfRadFaces+1]+deltaz};
6223 std::copy(conn,conn+4,ii);
6228 throw INTERP_KERNEL::Exception("A flat type has been detected that has not its extruded representation !");
6233 * This static operates only for coords in 3D. The polygon is specfied by its connectivity nodes in [begin,end).
6235 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const int *begin, const int *end, const double *coords)
6237 double v[3]={0.,0.,0.};
6238 std::size_t sz=std::distance(begin,end);
6241 for(std::size_t i=0;i<sz;i++)
6243 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];
6244 v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
6245 v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
6247 return vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2]>0.;
6251 * The polyhedron is specfied by its connectivity nodes in [begin,end).
6253 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const int *begin, const int *end, const double *coords)
6255 std::vector<std::pair<int,int> > edges;
6256 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
6257 const int *bgFace=begin;
6258 for(std::size_t i=0;i<nbOfFaces;i++)
6260 const int *endFace=std::find(bgFace+1,end,-1);
6261 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
6262 for(std::size_t j=0;j<nbOfEdgesInFace;j++)
6264 std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
6265 if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
6267 edges.push_back(p1);
6271 return INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)>-EPS_FOR_POLYH_ORIENTATION;
6275 * 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)
6276 * 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
6279 * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
6280 * \param [in] coords the coordinates with nb of components exactly equal to 3
6281 * \param [in] begin begin of the nodal connectivity (geometric type included) of a single polyhedron cell
6282 * \param [in] end end of nodal connectivity of a single polyhedron cell (excluded)
6283 * \param [out] the result is put at the end of the vector without any alteration of the data.
6285 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, const int *begin, const int *end, std::vector<int>& res) throw(INTERP_KERNEL::Exception)
6287 int nbFaces=std::count(begin+1,end,-1)+1;
6288 MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
6289 double *vPtr=v->getPointer();
6290 MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,1);
6291 double *pPtr=p->getPointer();
6292 const int *stFaceConn=begin+1;
6293 for(int i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
6295 const int *endFaceConn=std::find(stFaceConn,end,-1);
6296 ComputeVecAndPtOfFace(eps,coords->getConstPointer(),stFaceConn,endFaceConn,vPtr,pPtr);
6297 stFaceConn=endFaceConn+1;
6299 pPtr=p->getPointer(); vPtr=v->getPointer();
6300 DataArrayInt *comm1=0,*commI1=0;
6301 v->findCommonTuples(eps,-1,comm1,commI1);
6302 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> comm1Auto(comm1),commI1Auto(commI1);
6303 const int *comm1Ptr=comm1->getConstPointer();
6304 const int *commI1Ptr=commI1->getConstPointer();
6305 int nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
6306 res.push_back((int)INTERP_KERNEL::NORM_POLYHED);
6308 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> mm=MEDCouplingUMesh::New("",3);
6309 mm->setCoords(const_cast<DataArrayDouble *>(coords)); mm->allocateCells(1); mm->insertNextCell(INTERP_KERNEL::NORM_POLYHED,(int)std::distance(begin+1,end),begin+1);
6310 mm->finishInsertingCells();
6312 for(int i=0;i<nbOfGrps1;i++)
6314 int vecId=comm1Ptr[commI1Ptr[i]];
6315 MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
6316 DataArrayInt *comm2=0,*commI2=0;
6317 tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
6318 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> comm2Auto(comm2),commI2Auto(commI2);
6319 const int *comm2Ptr=comm2->getConstPointer();
6320 const int *commI2Ptr=commI2->getConstPointer();
6321 int nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
6322 for(int j=0;j<nbOfGrps2;j++)
6324 if(commI2Ptr[j+1]-commI2Ptr[j]<=1)
6326 res.insert(res.end(),begin,end);
6331 int pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
6332 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ids2=comm2->selectByTupleId2(commI2Ptr[j],commI2Ptr[j+1],1);
6333 ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
6334 DataArrayInt *tmp0=DataArrayInt::New(),*tmp1=DataArrayInt::New(),*tmp2=DataArrayInt::New(),*tmp3=DataArrayInt::New();
6335 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> mm2=mm->buildDescendingConnectivity(tmp0,tmp1,tmp2,tmp3); tmp0->decrRef(); tmp1->decrRef(); tmp2->decrRef(); tmp3->decrRef();
6336 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(mm2->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
6337 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> idsNodeTmp=mm3->zipCoordsTraducer();
6338 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
6339 const int *idsNodePtr=idsNode->getConstPointer();
6340 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];
6341 double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
6342 double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
6343 if(std::abs(norm)>eps)
6345 double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
6346 mm3->rotate(center,vec,angle);
6348 mm3->changeSpaceDimension(2);
6349 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
6350 const int *conn4=mm4->getNodalConnectivity()->getConstPointer();
6351 const int *connI4=mm4->getNodalConnectivityIndex()->getConstPointer();
6352 int nbOfCells=mm4->getNumberOfCells();
6353 for(int k=0;k<nbOfCells;k++)
6356 for(const int *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
6357 res.push_back(idsNodePtr[*work]);
6367 * 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
6368 * through origin. The plane is defined by its nodal connectivity [\b begin, \b end).
6370 * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
6371 * \param [in] coords coordinates expected to have 3 components.
6372 * \param [in] begin start of the nodal connectivity of the face.
6373 * \param [in] end end of the nodal connectivity (excluded) of the face.
6374 * \param [out] v the normalized vector of size 3
6375 * \param [out] p the pos of plane
6377 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const int *begin, const int *end, double *v, double *p) throw(INTERP_KERNEL::Exception)
6379 std::size_t nbPoints=std::distance(begin,end);
6381 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
6384 bool refFound=false;
6385 for(;j<nbPoints-1 && !refFound;j++)
6387 vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
6388 vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
6389 vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
6390 double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
6394 vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
6397 for(std::size_t i=j;i<nbPoints-1;i++)
6400 curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
6401 curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
6402 curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
6403 double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
6406 curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
6407 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];
6408 norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
6411 v[0]/=norm; v[1]/=norm; v[2]/=norm;
6412 *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
6416 throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
6420 * This method tries to obtain a well oriented polyhedron.
6421 * If the algorithm fails, an exception will be thrown.
6423 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(int *begin, int *end, const double *coords) throw(INTERP_KERNEL::Exception)
6425 std::vector<std::pair<int,int> > edges;
6426 std::size_t nbOfFaces=std::count(begin,end,-1)+1;
6428 std::vector<bool> isPerm(nbOfFaces);
6429 for(std::size_t i=0;i<nbOfFaces;i++)
6431 int *endFace=std::find(bgFace+1,end,-1);
6432 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
6433 for(std::size_t l=0;l<nbOfEdgesInFace;l++)
6435 std::pair<int,int> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]);
6436 edges.push_back(p1);
6438 int *bgFace2=endFace+1;
6439 for(std::size_t k=i+1;k<nbOfFaces;k++)
6441 int *endFace2=std::find(bgFace2+1,end,-1);
6442 std::size_t nbOfEdgesInFace2=std::distance(bgFace2,endFace2);
6443 for(std::size_t j=0;j<nbOfEdgesInFace2;j++)
6445 std::pair<int,int> p2(bgFace2[j],bgFace2[(j+1)%nbOfEdgesInFace2]);
6446 if(std::find(edges.begin(),edges.end(),p2)!=edges.end())
6449 throw INTERP_KERNEL::Exception("Fail to repare polyhedron ! Polyedron looks bad !");
6450 std::vector<int> tmp(nbOfEdgesInFace2-1);
6451 std::copy(bgFace2+1,endFace2,tmp.rbegin());
6452 std::copy(tmp.begin(),tmp.end(),bgFace2+1);
6461 if(INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)<-EPS_FOR_POLYH_ORIENTATION)
6462 {//not lucky ! The first face was not correctly oriented : reorient all faces...
6464 for(std::size_t i=0;i<nbOfFaces;i++)
6466 int *endFace=std::find(bgFace+1,end,-1);
6467 std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
6468 std::vector<int> tmp(nbOfEdgesInFace-1);
6469 std::copy(bgFace+1,endFace,tmp.rbegin());
6470 std::copy(tmp.begin(),tmp.end(),bgFace+1);
6477 * This method makes the assumption spacedimension == meshdimension == 2.
6478 * This method works only for linear cells.
6480 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
6482 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMesh() const throw(INTERP_KERNEL::Exception)
6484 if(getMeshDimension()!=2 || getSpaceDimension()!=2)
6485 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
6486 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m=computeSkin();
6487 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> o2n=m->zipCoordsTraducer();
6488 int nbOfNodesExpected=m->getNumberOfNodes();
6489 if(m->getNumberOfCells()!=nbOfNodesExpected)
6490 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part or a quadratic 2D mesh !");
6491 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> n2o=o2n->invertArrayO2N2N2O(m->getNumberOfNodes());
6492 const int *n2oPtr=n2o->getConstPointer();
6493 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revNodal(DataArrayInt::New()),revNodalI(DataArrayInt::New());
6494 m->getReverseNodalConnectivity(revNodal,revNodalI);
6495 const int *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
6496 const int *nodalPtr=m->getNodalConnectivity()->getConstPointer();
6497 const int *nodalIPtr=m->getNodalConnectivityIndex()->getConstPointer();
6498 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(nbOfNodesExpected+1,1);
6499 int *work=ret->getPointer(); *work++=INTERP_KERNEL::NORM_POLYGON;
6500 if(nbOfNodesExpected<1)
6501 { ret->incrRef(); return ret; }
6503 int prevNode=nodalPtr[nodalIPtr[0]+1];
6504 *work++=n2oPtr[prevNode];
6505 for(int i=1;i<nbOfNodesExpected;i++)
6507 if(nodalIPtr[prevCell+1]-nodalIPtr[prevCell]==3)
6509 std::set<int> conn(nodalPtr+nodalIPtr[prevCell]+1,nodalPtr+nodalIPtr[prevCell]+3);
6510 conn.erase(prevNode);
6513 int curNode=*(conn.begin());
6514 *work++=n2oPtr[curNode];
6515 std::set<int> shar(revNodalPtr+revNodalIPtr[curNode],revNodalPtr+revNodalIPtr[curNode+1]);
6516 shar.erase(prevCell);
6519 prevCell=*(shar.begin());
6523 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : presence of unexpected 2 !");
6526 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : presence of unexpected 1 !");
6529 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : presence of unexpected cell !");
6531 ret->incrRef(); return ret;
6535 * This method makes the assumption spacedimension == meshdimension == 3.
6536 * This method works only for linear cells.
6538 * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
6540 DataArrayInt *MEDCouplingUMesh::buildUnionOf3DMesh() const throw(INTERP_KERNEL::Exception)
6542 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6543 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
6544 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m=computeSkin();
6545 const int *conn=m->getNodalConnectivity()->getConstPointer();
6546 const int *connI=m->getNodalConnectivityIndex()->getConstPointer();
6547 int nbOfCells=m->getNumberOfCells();
6548 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
6549 int *work=ret->getPointer(); *work++=INTERP_KERNEL::NORM_POLYHED;
6551 { ret->incrRef(); return ret; }
6552 work=std::copy(conn+connI[0]+1,conn+connI[1],work);
6553 for(int i=1;i<nbOfCells;i++)
6556 work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
6563 * This method put in zip format into parameter 'zipFrmt' in full interlace mode.
6564 * This format is often asked by INTERP_KERNEL algorithms to avoid many indirections into coordinates array.
6566 void MEDCouplingUMesh::FillInCompact3DMode(int spaceDim, int nbOfNodesInCell, const int *conn, const double *coo, double *zipFrmt) throw(INTERP_KERNEL::Exception)
6570 for(int i=0;i<nbOfNodesInCell;i++)
6571 w=std::copy(coo+3*conn[i],coo+3*conn[i]+3,w);
6572 else if(spaceDim==2)
6574 for(int i=0;i<nbOfNodesInCell;i++)
6576 w=std::copy(coo+2*conn[i],coo+2*conn[i]+2,w);
6581 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::FillInCompact3DMode : Invalid spaceDim specified : must be 2 or 3 !");
6584 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData) const throw(INTERP_KERNEL::Exception)
6586 int nbOfCells=getNumberOfCells();
6588 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
6589 static const int PARAMEDMEM2VTKTYPETRADUCER[INTERP_KERNEL::NORM_MAXTYPE+1]={1,3,21,5,9,7,22,-1,23,-1,-1,-1,-1,-1,10,14,13,-1,12,-1,24,-1,16,27,-1,26,-1,-1,-1,-1,25,42,-1,4};
6590 ofs << " <" << getVTKDataSetType() << ">\n";
6591 ofs << " <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
6592 ofs << " <PointData>\n" << pointData << std::endl;
6593 ofs << " </PointData>\n";
6594 ofs << " <CellData>\n" << cellData << std::endl;
6595 ofs << " </CellData>\n";
6596 ofs << " <Points>\n";
6597 if(getSpaceDimension()==3)
6598 _coords->writeVTK(ofs,8,"Points");
6601 MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
6602 coo->writeVTK(ofs,8,"Points");
6604 ofs << " </Points>\n";
6605 ofs << " <Cells>\n";
6606 const int *cPtr=_nodal_connec->getConstPointer();
6607 const int *cIPtr=_nodal_connec_index->getConstPointer();
6608 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> faceoffsets=DataArrayInt::New(); faceoffsets->alloc(nbOfCells,1);
6609 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> types=DataArrayInt::New(); types->alloc(nbOfCells,1);
6610 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> offsets=DataArrayInt::New(); offsets->alloc(nbOfCells,1);
6611 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> connectivity=DataArrayInt::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
6612 int *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
6613 int szFaceOffsets=0,szConn=0;
6614 for(int i=0;i<nbOfCells;i++,w1++,w2++,w3++)
6617 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
6620 *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
6621 w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
6625 int deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
6626 *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
6627 std::set<int> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
6628 *w3=szConn+(int)c.size(); szConn+=(int)c.size();
6629 w4=std::copy(c.begin(),c.end(),w4);
6632 types->transformWithIndArr(PARAMEDMEM2VTKTYPETRADUCER,PARAMEDMEM2VTKTYPETRADUCER+INTERP_KERNEL::NORM_MAXTYPE);
6633 types->writeVTK(ofs,8,"UInt8","types");
6634 offsets->writeVTK(ofs,8,"Int32","offsets");
6635 if(szFaceOffsets!=0)
6636 {//presence of Polyhedra
6637 connectivity->reAlloc(szConn);
6638 faceoffsets->writeVTK(ofs,8,"Int32","faceoffsets");
6639 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> faces=DataArrayInt::New(); faces->alloc(szFaceOffsets,1);
6640 w1=faces->getPointer();
6641 for(int i=0;i<nbOfCells;i++)
6642 if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
6644 int nbFaces=std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1)+1;
6646 const int *w6=cPtr+cIPtr[i]+1,*w5=0;
6647 for(int j=0;j<nbFaces;j++)
6649 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
6650 *w1++=(int)std::distance(w6,w5);
6651 w1=std::copy(w6,w5,w1);
6655 faces->writeVTK(ofs,8,"Int32","faces");
6657 connectivity->writeVTK(ofs,8,"Int32","connectivity");
6658 ofs << " </Cells>\n";
6659 ofs << " </Piece>\n";
6660 ofs << " </" << getVTKDataSetType() << ">\n";
6663 std::string MEDCouplingUMesh::getVTKDataSetType() const throw(INTERP_KERNEL::Exception)
6665 return std::string("UnstructuredGrid");
6670 MEDCouplingUMesh *MEDCouplingUMesh::Intersect2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2, double eps, DataArrayInt *&cellNb1, DataArrayInt *&cellNb2) throw(INTERP_KERNEL::Exception)
6672 m1->checkFullyDefined();
6673 m2->checkFullyDefined();
6674 if(m1->getMeshDimension()!=2 || m1->getSpaceDimension()!=2 || m2->getMeshDimension()!=2 || m2->getSpaceDimension()!=2)
6675 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshes works on umeshes m1 AND m2 with meshdim equal to 2 and spaceDim equal to 2 too!");
6676 std::vector< std::vector<int> > intersectEdge1, colinear2, subDiv2;
6677 MEDCouplingUMesh *m1Desc=0,*m2Desc=0;
6678 DataArrayInt *desc1=0,*descIndx1=0,*revDesc1=0,*revDescIndx1=0,*desc2=0,*descIndx2=0,*revDesc2=0,*revDescIndx2=0;
6679 std::vector<double> addCoo,addCoordsQuadratic;
6680 INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
6681 INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
6682 IntersectDescending2DMeshes(m1,m2,eps,intersectEdge1,colinear2, subDiv2,m1Desc,desc1,descIndx1,revDesc1,revDescIndx1,
6683 m2Desc,desc2,descIndx2,revDesc2,revDescIndx2,addCoo);
6684 revDesc1->decrRef(); revDescIndx1->decrRef(); revDesc2->decrRef(); revDescIndx2->decrRef();
6685 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(desc2),dd4(descIndx2);
6686 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> dd5(m1Desc),dd6(m2Desc);
6687 std::vector< std::vector<int> > intersectEdge2;
6688 BuildIntersectEdges(m1Desc,m2Desc,addCoo,subDiv2,intersectEdge2);
6689 subDiv2.clear(); dd5=0; dd6=0;
6690 std::vector<int> cr,crI;
6691 std::vector<int> cNb1,cNb2;
6692 BuildIntersecting2DCellsFromEdges(eps,m1,desc1->getConstPointer(),descIndx1->getConstPointer(),intersectEdge1,colinear2,m2,desc2->getConstPointer(),descIndx2->getConstPointer(),intersectEdge2,addCoo,
6693 /* outputs -> */addCoordsQuadratic,cr,crI,cNb1,cNb2);
6695 MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> addCooDa=DataArrayDouble::New();
6696 addCooDa->alloc((int)(addCoo.size())/2,2);
6697 std::copy(addCoo.begin(),addCoo.end(),addCooDa->getPointer());
6698 MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> addCoordsQuadraticDa=DataArrayDouble::New();
6699 addCoordsQuadraticDa->alloc((int)(addCoordsQuadratic.size())/2,2);
6700 std::copy(addCoordsQuadratic.begin(),addCoordsQuadratic.end(),addCoordsQuadraticDa->getPointer());
6701 std::vector<const DataArrayDouble *> coordss(4);
6702 coordss[0]=m1->getCoords(); coordss[1]=m2->getCoords(); coordss[2]=addCooDa; coordss[3]=addCoordsQuadraticDa;
6703 MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> coo=DataArrayDouble::Aggregate(coordss);
6704 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Intersect2D",2);
6705 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> conn=DataArrayInt::New(); conn->alloc((int)cr.size(),1); std::copy(cr.begin(),cr.end(),conn->getPointer());
6706 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> connI=DataArrayInt::New(); connI->alloc((int)crI.size(),1); std::copy(crI.begin(),crI.end(),connI->getPointer());
6707 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> c1=DataArrayInt::New(); c1->alloc((int)cNb1.size(),1); std::copy(cNb1.begin(),cNb1.end(),c1->getPointer()); cellNb1=c1;
6708 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> c2=DataArrayInt::New(); c2->alloc((int)cNb2.size(),1); std::copy(cNb2.begin(),cNb2.end(),c2->getPointer()); cellNb2=c2;
6709 ret->setConnectivity(conn,connI,true);
6710 ret->setCoords(coo);
6711 ret->incrRef(); c1->incrRef(); c2->incrRef();
6717 void MEDCouplingUMesh::BuildIntersecting2DCellsFromEdges(double eps, const MEDCouplingUMesh *m1, const int *desc1, const int *descIndx1,
6718 const std::vector<std::vector<int> >& intesctEdges1, const std::vector< std::vector<int> >& colinear2,
6719 const MEDCouplingUMesh *m2, const int *desc2, const int *descIndx2, const std::vector<std::vector<int> >& intesctEdges2,
6720 const std::vector<double>& addCoords,
6721 std::vector<double>& addCoordsQuadratic, std::vector<int>& cr, std::vector<int>& crI, std::vector<int>& cNb1, std::vector<int>& cNb2)
6723 static const int SPACEDIM=2;
6724 std::vector<double> bbox1,bbox2;
6725 const double *coo1=m1->getCoords()->getConstPointer();
6726 const int *conn1=m1->getNodalConnectivity()->getConstPointer();
6727 const int *connI1=m1->getNodalConnectivityIndex()->getConstPointer();
6728 int offset1=m1->getNumberOfNodes();
6729 const double *coo2=m2->getCoords()->getConstPointer();
6730 const int *conn2=m2->getNodalConnectivity()->getConstPointer();
6731 const int *connI2=m2->getNodalConnectivityIndex()->getConstPointer();
6732 int offset2=offset1+m2->getNumberOfNodes();
6733 int offset3=offset2+((int)addCoords.size())/2;
6734 m1->getBoundingBoxForBBTree(bbox1);
6735 m2->getBoundingBoxForBBTree(bbox2);
6736 BBTree<SPACEDIM,int> myTree(&bbox2[0],0,0,m2->getNumberOfCells(),eps);
6737 int ncell1=m1->getNumberOfCells();
6739 for(int i=0;i<ncell1;i++)
6741 std::vector<int> candidates2;
6742 myTree.getIntersectingElems(&bbox1[i*2*SPACEDIM],candidates2);
6743 std::map<INTERP_KERNEL::Node *,int> mapp;
6744 std::map<int,INTERP_KERNEL::Node *> mappRev;
6745 INTERP_KERNEL::QuadraticPolygon pol1;
6746 INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn1[connI1[i]];
6747 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6748 MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,/* output */mapp,mappRev);
6749 pol1.buildFromCrudeDataArray(mappRev,cm.isQuadratic(),conn1+connI1[i]+1,coo1,
6750 desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1);
6752 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
6753 std::set<INTERP_KERNEL::Edge *> edgesBoundary2;// store all edges that are on boundary of (pol2 intersect pol1) minus edges on pol1.
6754 INTERP_KERNEL::IteratorOnComposedEdge it1(&pol1);
6755 for(it1.first();!it1.finished();it1.next())
6756 edges1.insert(it1.current()->getPtr());
6758 std::map<int,std::vector<INTERP_KERNEL::ElementaryEdge *> > edgesIn2ForShare;
6759 std::vector<INTERP_KERNEL::QuadraticPolygon> pol2s(candidates2.size());
6761 for(std::vector<int>::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++,ii++)
6763 INTERP_KERNEL::NormalizedCellType typ2=(INTERP_KERNEL::NormalizedCellType)conn2[connI2[*it2]];
6764 const INTERP_KERNEL::CellModel& cm2=INTERP_KERNEL::CellModel::GetCellModel(typ2);
6765 MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,/* output */mapp,mappRev);
6766 pol2s[ii].buildFromCrudeDataArray2(mappRev,cm2.isQuadratic(),conn2+connI2[*it2]+1,coo2,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,
6767 pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2,edgesIn2ForShare);
6770 for(std::vector<int>::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++,ii++)
6772 pol1.initLocationsWithOther(pol2s[ii]);
6773 pol2s[ii].updateLocOfEdgeFromCrudeDataArray2(desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2);
6774 //MEDCouplingUMeshAssignOnLoc(pol1,pol2,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,colinear2);
6775 pol1.buildPartitionsAbs(pol2s[ii],edges1,edgesBoundary2,mapp,i,*it2,offset3,addCoordsQuadratic,cr,crI,cNb1,cNb2);
6779 INTERP_KERNEL::QuadraticPolygon::ComputeResidual(pol1,edges1,edgesBoundary2,mapp,offset3,i,addCoordsQuadratic,cr,crI,cNb1,cNb2);
6781 for(std::map<int,INTERP_KERNEL::Node *>::const_iterator it=mappRev.begin();it!=mappRev.end();it++)
6782 (*it).second->decrRef();
6787 * This method is private and is the first step of Partition of 2D mesh (spaceDim==2 and meshDim==2).
6790 void MEDCouplingUMesh::IntersectDescending2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2, double eps,
6791 std::vector< std::vector<int> >& intersectEdge1, std::vector< std::vector<int> >& colinear2, std::vector< std::vector<int> >& subDiv2,
6792 MEDCouplingUMesh *& m1Desc, DataArrayInt *&desc1, DataArrayInt *&descIndx1, DataArrayInt *&revDesc1, DataArrayInt *&revDescIndx1,
6793 MEDCouplingUMesh *& m2Desc, DataArrayInt *&desc2, DataArrayInt *&descIndx2, DataArrayInt *&revDesc2, DataArrayInt *&revDescIndx2,
6794 std::vector<double>& addCoo) throw(INTERP_KERNEL::Exception)
6796 static const int SPACEDIM=2;
6797 desc1=DataArrayInt::New(); descIndx1=DataArrayInt::New(); revDesc1=DataArrayInt::New(); revDescIndx1=DataArrayInt::New();
6798 desc2=DataArrayInt::New();
6799 descIndx2=DataArrayInt::New();
6800 revDesc2=DataArrayInt::New();
6801 revDescIndx2=DataArrayInt::New();
6802 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(revDesc1),dd4(revDescIndx1);
6803 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> dd5(desc2),dd6(descIndx2),dd7(revDesc2),dd8(revDescIndx2);
6804 m1Desc=m1->buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1);
6805 m2Desc=m2->buildDescendingConnectivity2(desc2,descIndx2,revDesc2,revDescIndx2);
6806 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> dd9(m1Desc),dd10(m2Desc);
6807 const int *c1=m1Desc->getNodalConnectivity()->getConstPointer();
6808 const int *ci1=m1Desc->getNodalConnectivityIndex()->getConstPointer();
6809 std::vector<double> bbox1,bbox2;
6810 m1Desc->getBoundingBoxForBBTree(bbox1);
6811 m2Desc->getBoundingBoxForBBTree(bbox2);
6812 int ncell1=m1Desc->getNumberOfCells();
6813 int ncell2=m2Desc->getNumberOfCells();
6814 intersectEdge1.resize(ncell1);
6815 colinear2.resize(ncell2);
6816 subDiv2.resize(ncell2);
6817 BBTree<SPACEDIM,int> myTree(&bbox2[0],0,0,m2Desc->getNumberOfCells(),-eps);
6818 std::vector<int> candidates1(1);
6819 int offset1=m1->getNumberOfNodes();
6820 int offset2=offset1+m2->getNumberOfNodes();
6821 for(int i=0;i<ncell1;i++)
6823 std::vector<int> candidates2;
6824 myTree.getIntersectingElems(&bbox1[i*2*SPACEDIM],candidates2);
6825 if(!candidates2.empty())
6827 std::map<INTERP_KERNEL::Node *,int> map1,map2;
6828 INTERP_KERNEL::QuadraticPolygon *pol2=MEDCouplingUMeshBuildQPFromMesh(m2Desc,candidates2,map2);
6830 INTERP_KERNEL::QuadraticPolygon *pol1=MEDCouplingUMeshBuildQPFromMesh(m1Desc,candidates1,map1);
6831 pol1->splitAbs(*pol2,map1,map2,offset1,offset2,candidates2,intersectEdge1[i],i,colinear2,subDiv2,addCoo);
6836 intersectEdge1[i].insert(intersectEdge1[i].end(),c1+ci1[i]+1,c1+ci1[i+1]);
6838 m1Desc->incrRef(); desc1->incrRef(); descIndx1->incrRef(); revDesc1->incrRef(); revDescIndx1->incrRef();
6839 m2Desc->incrRef(); desc2->incrRef(); descIndx2->incrRef(); revDesc2->incrRef(); revDescIndx2->incrRef();
6843 * This method performs the 2nd step of Partition of 2D mesh.
6844 * This method has 4 inputs :
6845 * - a mesh 'm1' with meshDim==1 and a SpaceDim==2
6846 * - a mesh 'm2' with meshDim==1 and a SpaceDim==2
6847 * - subDiv of size 'm2->getNumberOfCells()' that lists for each seg cell in 'm' the splitting node ids in randomly sorted.
6848 * The aim of this method is to sort the splitting nodes, if any, and to put in 'intersectEdge' output paramter based on edges of mesh 'm2'
6849 * @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. Only present for its coords in case of 'subDiv' shares some nodes of 'm1'
6850 * @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.
6851 * @param addCoo input parameter with additionnal nodes linked to intersection of the 2 meshes.
6853 void MEDCouplingUMesh::BuildIntersectEdges(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2, const std::vector<double>& addCoo, const std::vector< std::vector<int> >& subDiv, std::vector< std::vector<int> >& intersectEdge) throw(INTERP_KERNEL::Exception)
6855 int offset1=m1->getNumberOfNodes();
6856 int ncell=m2->getNumberOfCells();
6857 const int *c=m2->getNodalConnectivity()->getConstPointer();
6858 const int *cI=m2->getNodalConnectivityIndex()->getConstPointer();
6859 const double *coo=m2->getCoords()->getConstPointer();
6860 const double *cooBis=m1->getCoords()->getConstPointer();
6861 int offset2=offset1+m2->getNumberOfNodes();
6862 intersectEdge.resize(ncell);
6863 for(int i=0;i<ncell;i++,cI++)
6865 const std::vector<int>& divs=subDiv[i];
6866 int nnode=cI[1]-cI[0]-1;
6867 std::map<int, std::pair<INTERP_KERNEL::Node *,bool> > mapp2;
6868 std::map<INTERP_KERNEL::Node *, int> mapp22;
6869 for(int j=0;j<nnode;j++)
6871 INTERP_KERNEL::Node *nn=new INTERP_KERNEL::Node(coo[2*c[(*cI)+j+1]],coo[2*c[(*cI)+j+1]+1]);
6872 int nnid=c[(*cI)+j+1];
6873 mapp2[nnid]=std::pair<INTERP_KERNEL::Node *,bool>(nn,true);
6874 mapp22[nn]=nnid+offset1;
6876 INTERP_KERNEL::Edge *e=MEDCouplingUMeshBuildQPFromEdge((INTERP_KERNEL::NormalizedCellType)c[*cI],mapp2,c+(*cI)+1);
6877 for(std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >::const_iterator it=mapp2.begin();it!=mapp2.end();it++)
6878 ((*it).second.first)->decrRef();
6879 std::vector<INTERP_KERNEL::Node *> addNodes(divs.size());
6880 std::map<INTERP_KERNEL::Node *,int> mapp3;
6881 for(std::size_t j=0;j<divs.size();j++)
6884 INTERP_KERNEL::Node *tmp=0;
6886 tmp=new INTERP_KERNEL::Node(cooBis[2*id],cooBis[2*id+1]);
6888 tmp=new INTERP_KERNEL::Node(coo[2*(id-offset1)],coo[2*(id-offset1)+1]);//if it happens, bad news mesh 'm2' is non conform.
6890 tmp=new INTERP_KERNEL::Node(addCoo[2*(id-offset2)],addCoo[2*(id-offset2)+1]);
6894 e->sortIdsAbs(addNodes,mapp22,mapp3,intersectEdge[i]);
6895 for(std::vector<INTERP_KERNEL::Node *>::const_iterator it=addNodes.begin();it!=addNodes.end();it++)
6902 * 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).
6903 * 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
6904 * with a plane. The result will be put in 'cut3DSuf' out parameter.
6905 * @param cut3DCurve input paramter that gives for each 3DCurve cell if it owns fully to the plane or partially.
6906 * @param nodesOnPlane, returns all the nodes that are on the plane.
6907 * @param nodal3DSurf is the nodal connectivity of 3D surf mesh.
6908 * @param nodalIndx3DSurf is the nodal connectivity index of 3D surf mesh.
6909 * @param nodal3DCurve is the nodal connectivity of 3D curve mesh.
6910 * @param nodal3DIndxCurve is the nodal connectivity index of 3D curve mesh.
6911 * @param desc is the descending connectivity 3DSurf->3DCurve
6912 * @param descIndx is the descending connectivity index 3DSurf->3DCurve
6913 * @param cut3DSuf input/output param.
6915 void MEDCouplingUMesh::AssemblyForSplitFrom3DCurve(const std::vector<int>& cut3DCurve, std::vector<int>& nodesOnPlane, const int *nodal3DSurf, const int *nodalIndx3DSurf,
6916 const int *nodal3DCurve, const int *nodalIndx3DCurve,
6917 const int *desc, const int *descIndx,
6918 std::vector< std::pair<int,int> >& cut3DSurf) throw(INTERP_KERNEL::Exception)
6920 std::set<int> nodesOnP(nodesOnPlane.begin(),nodesOnPlane.end());
6921 int nbOf3DSurfCell=(int)cut3DSurf.size();
6922 for(int i=0;i<nbOf3DSurfCell;i++)
6924 std::vector<int> res;
6925 int offset=descIndx[i];
6926 int nbOfSeg=descIndx[i+1]-offset;
6927 for(int j=0;j<nbOfSeg;j++)
6929 int edgeId=desc[offset+j];
6930 int status=cut3DCurve[edgeId];
6934 res.push_back(status);
6937 res.push_back(nodal3DCurve[nodalIndx3DCurve[edgeId]+1]);
6938 res.push_back(nodal3DCurve[nodalIndx3DCurve[edgeId]+2]);
6946 cut3DSurf[i].first=res[0]; cut3DSurf[i].second=res[1];
6952 std::set<int> s1(nodal3DSurf+nodalIndx3DSurf[i]+1,nodal3DSurf+nodalIndx3DSurf[i+1]);
6953 std::set_intersection(nodesOnP.begin(),nodesOnP.end(),s1.begin(),s1.end(),std::back_insert_iterator< std::vector<int> >(res));
6956 cut3DSurf[i].first=res[0]; cut3DSurf[i].second=res[1];
6960 cut3DSurf[i].first=-1; cut3DSurf[i].second=-1;
6965 {// case when plane is on a multi colinear edge of a polyhedron
6966 if((int)res.size()==2*nbOfSeg)
6968 cut3DSurf[i].first=-2; cut3DSurf[i].second=i;
6971 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AssemblyPointsFrom3DCurve : unexpected situation !");
6978 * 'this' is expected to be a mesh with spaceDim==3 and meshDim==3. If not an exception will be thrown.
6979 * 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).
6980 * 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
6981 * with a plane. The result will be put in 'nodalRes' 'nodalResIndx' and 'cellIds' out parameters.
6982 * @param cut3DSurf input paramter that gives for each 3DSurf its intersection with plane (result of MEDCouplingUMesh::AssemblyForSplitFrom3DCurve).
6983 * @param desc is the descending connectivity 3D->3DSurf
6984 * @param descIndx is the descending connectivity index 3D->3DSurf
6986 void MEDCouplingUMesh::assemblyForSplitFrom3DSurf(const std::vector< std::pair<int,int> >& cut3DSurf,
6987 const int *desc, const int *descIndx,
6988 std::vector<int>& nodalRes, std::vector<int>& nodalResIndx, std::vector<int>& cellIds) const throw(INTERP_KERNEL::Exception)
6990 checkFullyDefined();
6991 if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6992 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::assemblyForSplitFrom3DSurf works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
6993 const int *nodal3D=_nodal_connec->getConstPointer();
6994 const int *nodalIndx3D=_nodal_connec_index->getConstPointer();
6995 int nbOfCells=getNumberOfCells();
6996 for(int i=0;i<nbOfCells;i++)
6998 std::map<int, std::set<int> > m;
6999 int offset=descIndx[i];
7000 int nbOfFaces=descIndx[i+1]-offset;
7003 for(int j=0;j<nbOfFaces;j++)
7005 const std::pair<int,int>& p=cut3DSurf[desc[offset+j]];
7006 if(p.first!=-1 && p.second!=-1)
7010 start=p.first; end=p.second;
7011 m[p.first].insert(p.second);
7012 m[p.second].insert(p.first);
7016 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodal3D[nodalIndx3D[i]]);
7017 int sz=nodalIndx3D[i+1]-nodalIndx3D[i]-1;
7018 INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
7019 INTERP_KERNEL::NormalizedCellType cmsId;
7020 unsigned nbOfNodesSon=cm.fillSonCellNodalConnectivity2(j,nodal3D+nodalIndx3D[i]+1,sz,tmp,cmsId);
7021 start=tmp[0]; end=tmp[nbOfNodesSon-1];
7022 for(unsigned k=0;k<nbOfNodesSon;k++)
7024 m[tmp[k]].insert(tmp[(k+1)%nbOfNodesSon]);
7025 m[tmp[(k+1)%nbOfNodesSon]].insert(tmp[k]);
7032 std::vector<int> conn(1,(int)INTERP_KERNEL::NORM_POLYGON);
7036 std::map<int, std::set<int> >::const_iterator it=m.find(start);
7037 const std::set<int>& s=(*it).second;
7038 std::set<int> s2; s2.insert(prev);
7040 std::set_difference(s.begin(),s.end(),s2.begin(),s2.end(),inserter(s3,s3.begin()));
7043 int val=*s3.begin();
7044 conn.push_back(start);
7051 conn.push_back(end);
7054 nodalRes.insert(nodalRes.end(),conn.begin(),conn.end());
7055 nodalResIndx.push_back((int)nodalRes.size());
7056 cellIds.push_back(i);
7062 * 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
7063 * 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
7064 * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
7065 * 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
7066 * 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.
7068 * @return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
7070 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const int *nodalConnBg, const int *nodalConnEnd, std::vector<int>& nodalConnecOut) throw(INTERP_KERNEL::Exception)
7072 std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
7075 const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
7076 if(cm.getDimension()==2)
7078 const int *node=nodalConnBg+1;
7079 int startNode=*node++;
7080 double refX=coords[2*startNode];
7081 for(;node!=nodalConnEnd;node++)
7083 if(coords[2*(*node)]<refX)
7086 refX=coords[2*startNode];
7089 std::vector<int> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
7093 double angle0=-M_PI/2;
7099 while(nextNode!=startNode)
7103 for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
7105 if(*node!=tmpOut.back() && *node!=prevNode)
7107 tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
7108 double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
7113 res=angle0-angleM+2.*M_PI;
7122 if(nextNode!=startNode)
7124 angle0=angleNext-M_PI;
7127 prevNode=tmpOut.back();
7128 tmpOut.push_back(nextNode);
7131 std::vector<int> tmp3(2*(sz-1));
7132 std::vector<int>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
7133 std::copy(nodalConnBg+1,nodalConnEnd,it);
7134 if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
7136 nodalConnecOut.insert(nodalConnecOut.end(),nodalConnBg,nodalConnEnd);
7139 if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
7141 nodalConnecOut.insert(nodalConnecOut.end(),nodalConnBg,nodalConnEnd);
7146 nodalConnecOut.push_back((int)INTERP_KERNEL::NORM_POLYGON);
7147 nodalConnecOut.insert(nodalConnecOut.end(),tmpOut.begin(),tmpOut.end());
7152 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7155 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7159 * This method works on an input pair (\b arr, \b arrIndx) where \b arr indexes is in \b arrIndx.
7160 * 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.
7162 * \param [in] idsToRemoveBg begin of set of ids to remove in \b arr (included)
7163 * \param [in] idsToRemoveEnd end of set of ids to remove in \b arr (excluded)
7164 * \param [in,out] arr array in which the remove operation will be done.
7165 * \param [in,out] arrIndx array in the remove operation will modify
7166 * \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])
7167 * \return true if \b arr and \b arrIndx have been modified, false if not.
7169 bool MEDCouplingUMesh::RemoveIdsFromIndexedArrays(const int *idsToRemoveBg, const int *idsToRemoveEnd, DataArrayInt *arr, DataArrayInt *arrIndx, int offsetForRemoval) throw(INTERP_KERNEL::Exception)
7171 if(!arrIndx || !arr)
7172 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : some input arrays are empty !");
7173 if(offsetForRemoval<0)
7174 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : offsetForRemoval should be >=0 !");
7175 std::set<int> s(idsToRemoveBg,idsToRemoveEnd);
7176 int nbOfGrps=arrIndx->getNumberOfTuples()-1;
7177 int *arrIPtr=arrIndx->getPointer();
7180 const int *arrPtr=arr->getConstPointer();
7181 std::vector<int> arrOut;
7182 for(int i=0;i<nbOfGrps;i++,arrIPtr++)
7184 if(*arrIPtr-previousArrI>offsetForRemoval)
7186 for(const int *work=arrPtr+previousArrI+offsetForRemoval;work!=arrPtr+*arrIPtr;work++)
7188 if(s.find(*work)==s.end())
7189 arrOut.push_back(*work);
7192 previousArrI=*arrIPtr;
7193 *arrIPtr=(int)arrOut.size();
7195 if(arr->getNumberOfTuples()==(int)arrOut.size())
7197 arr->alloc((int)arrOut.size(),1);
7198 std::copy(arrOut.begin(),arrOut.end(),arr->getPointer());
7203 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
7204 * This method returns the result of the extraction ( specified by a set of ids in [\b idsOfSelectBg , \b idsOfSelectEnd ) ).
7205 * The selection of extraction is done standardly in new2old format.
7206 * This method returns indexed arrays using 2 arrays (arrOut,arrIndexOut).
7208 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
7209 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
7210 * \param [in] arrIn arr origin array from which the extraction will be done.
7211 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7212 * \param [out] arrOut the resulting array
7213 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
7215 void MEDCouplingUMesh::ExtractFromIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
7216 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut) throw(INTERP_KERNEL::Exception)
7218 if(!arrIn || !arrIndxIn)
7219 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input pointer is NULL !");
7220 std::size_t sz=std::distance(idsOfSelectBg,idsOfSelectEnd);
7221 const int *arrInPtr=arrIn->getConstPointer();
7222 const int *arrIndxPtr=arrIndxIn->getConstPointer();
7223 int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
7224 int maxSizeOfArr=arrIn->getNumberOfTuples();
7225 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> arro=DataArrayInt::New();
7226 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> arrIo=DataArrayInt::New();
7227 arrIo->alloc((int)(sz+1),1);
7228 const int *idsIt=idsOfSelectBg;
7229 int *work=arrIo->getPointer();
7232 for(std::size_t i=0;i<sz;i++,work++,idsIt++)
7234 if(*idsIt>=0 && *idsIt<nbOfGrps)
7235 lgth+=arrIndxPtr[*idsIt+1]-arrIndxPtr[*idsIt];
7238 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " ! Must be in [0," << nbOfGrps << ") !";
7239 throw INTERP_KERNEL::Exception(oss.str().c_str());
7245 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " and at this pos arrIndxIn[" << *idsIt;
7246 oss << "+1]-arrIndxIn[" << *idsIt << "] < 0 ! The input index array is bugged !";
7247 throw INTERP_KERNEL::Exception(oss.str().c_str());
7250 arro->alloc(lgth,1);
7251 work=arro->getPointer();
7252 idsIt=idsOfSelectBg;
7253 for(std::size_t i=0;i<sz;i++,idsIt++)
7255 if(arrIndxPtr[*idsIt]>=0 && arrIndxPtr[*idsIt+1]<=maxSizeOfArr)
7256 work=std::copy(arrInPtr+arrIndxPtr[*idsIt],arrInPtr+arrIndxPtr[*idsIt+1],work);
7259 std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " arrIndx[" << *idsIt << "] must be >= 0 and arrIndx[";
7260 oss << *idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
7261 throw INTERP_KERNEL::Exception(oss.str().c_str());
7271 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
7272 * 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
7273 * cellIds \b in [\b idsOfSelectBg, \b idsOfSelectEnd) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
7274 * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
7276 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
7277 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
7278 * \param [in] arrIn arr origin array from which the extraction will be done.
7279 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7280 * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
7281 * \param [in] srcArrIndex index array of \b srcArr
7282 * \param [out] arrOut the resulting array
7283 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
7285 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
7287 void MEDCouplingUMesh::SetPartOfIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
7288 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
7289 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut) throw(INTERP_KERNEL::Exception)
7291 if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
7292 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArrays : presence of null pointer in input parameter !");
7293 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> arro=DataArrayInt::New();
7294 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> arrIo=DataArrayInt::New();
7295 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7296 std::vector<bool> v(nbOfTuples,true);
7298 const int *arrIndxInPtr=arrIndxIn->getConstPointer();
7299 const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
7300 for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
7302 if(*it>=0 && *it<nbOfTuples)
7305 offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[*it+1]-arrIndxInPtr[*it]);
7309 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArrays : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
7310 throw INTERP_KERNEL::Exception(oss.str().c_str());
7313 srcArrIndexPtr=srcArrIndex->getConstPointer();
7314 arrIo->alloc(nbOfTuples+1,1);
7315 arro->alloc(arrIn->getNumberOfTuples()+offset,1);
7316 const int *arrInPtr=arrIn->getConstPointer();
7317 const int *srcArrPtr=srcArr->getConstPointer();
7318 int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
7319 int *arroPtr=arro->getPointer();
7320 for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
7324 arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
7325 *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
7329 std::size_t pos=std::distance(idsOfSelectBg,std::find(idsOfSelectBg,idsOfSelectEnd,ii));
7330 arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
7331 *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
7334 arrOut=arro; arro->incrRef();
7335 arrIndexOut=arrIo; arrIo->incrRef();
7339 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
7340 * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
7342 * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
7343 * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
7344 * \param [in,out] arrInOut arr origin array from which the extraction will be done.
7345 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7346 * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
7347 * \param [in] srcArrIndex index array of \b srcArr
7349 * \sa MEDCouplingUMesh::SetPartOfIndexedArrays
7351 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(const int *idsOfSelectBg, const int *idsOfSelectEnd, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
7352 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex) throw(INTERP_KERNEL::Exception)
7354 if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
7355 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : presence of null pointer in input parameter !");
7356 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7357 const int *arrIndxInPtr=arrIndxIn->getConstPointer();
7358 const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
7359 int *arrInOutPtr=arrInOut->getPointer();
7360 const int *srcArrPtr=srcArr->getConstPointer();
7361 for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
7363 if(*it>=0 && *it<nbOfTuples)
7365 if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[*it+1]-arrIndxInPtr[*it])
7366 std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[*it]);
7369 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] !";
7370 throw INTERP_KERNEL::Exception(oss.str().c_str());
7375 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
7376 throw INTERP_KERNEL::Exception(oss.str().c_str());
7382 * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
7383 * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
7384 * 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]].
7385 * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
7386 * A negative value in \b arrIn means that it is ignored.
7387 * This method is usefull 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.
7389 * \param [in] arrIn arr origin array from which the extraction will be done.
7390 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7391 * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
7393 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn) throw(INTERP_KERNEL::Exception)
7395 if(!arrIn || !arrIndxIn)
7396 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input pointer is NULL !");
7397 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7400 DataArrayInt *ret=DataArrayInt::New(); ret->alloc(0,1);
7403 const int *arrInPtr=arrIn->getConstPointer();
7404 const int *arrIndxPtr=arrIndxIn->getConstPointer();
7405 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> arro=DataArrayInt::New();
7406 arro->alloc(nbOfTuples,1);
7407 arro->fillWithValue(-1);
7408 int *arroPtr=arro->getPointer();
7409 std::set<int> s; s.insert(0);
7413 for(std::set<int>::const_iterator it=s.begin();it!=s.end();it++)
7415 for(const int *work=arrInPtr+arrIndxPtr[*it];work!=arrInPtr+arrIndxPtr[*it+1];work++)
7417 if(*work>=0 && arroPtr[*work]<0)
7426 return arro->getIdsEqual(1);
7430 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
7431 * 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
7432 * cellIds \b in [\b idsOfSelectBg, \b idsOfSelectEnd) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
7433 * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
7435 * \param [in] start begin of set of ids of the input extraction (included)
7436 * \param [in] end end of set of ids of the input extraction (excluded)
7437 * \param [in] step step of the set of ids in range mode.
7438 * \param [in] arrIn arr origin array from which the extraction will be done.
7439 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7440 * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
7441 * \param [in] srcArrIndex index array of \b srcArr
7442 * \param [out] arrOut the resulting array
7443 * \param [out] arrIndexOut the index array of the resulting array \b arrOut
7445 * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx MEDCouplingUMesh::SetPartOfIndexedArrays
7447 void MEDCouplingUMesh::SetPartOfIndexedArrays2(int start, int end, int step, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
7448 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
7449 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut) throw(INTERP_KERNEL::Exception)
7451 if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
7452 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArrays2 : presence of null pointer in input parameter !");
7453 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> arro=DataArrayInt::New();
7454 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> arrIo=DataArrayInt::New();
7455 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7457 const int *arrIndxInPtr=arrIndxIn->getConstPointer();
7458 const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
7459 int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArrays2 : ");
7461 for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
7463 if(it>=0 && it<nbOfTuples)
7464 offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[it+1]-arrIndxInPtr[it]);
7467 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArrays2 : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
7468 throw INTERP_KERNEL::Exception(oss.str().c_str());
7471 srcArrIndexPtr=srcArrIndex->getConstPointer();
7472 arrIo->alloc(nbOfTuples+1,1);
7473 arro->alloc(arrIn->getNumberOfTuples()+offset,1);
7474 const int *arrInPtr=arrIn->getConstPointer();
7475 const int *srcArrPtr=srcArr->getConstPointer();
7476 int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
7477 int *arroPtr=arro->getPointer();
7478 for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
7480 int pos=DataArray::GetPosOfItemGivenBESRelativeNoThrow(ii,start,end,step);
7483 arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
7484 *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
7488 arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
7489 *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
7492 arrOut=arro; arro->incrRef();
7493 arrIndexOut=arrIo; arrIo->incrRef();
7497 * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
7498 * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
7500 * \param [in] start begin of set of ids of the input extraction (included)
7501 * \param [in] end end of set of ids of the input extraction (excluded)
7502 * \param [in] step step of the set of ids in range mode.
7503 * \param [in,out] arrInOut arr origin array from which the extraction will be done.
7504 * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7505 * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
7506 * \param [in] srcArrIndex index array of \b srcArr
7508 * \sa MEDCouplingUMesh::SetPartOfIndexedArrays2 MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
7510 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx2(int start, int end, int step, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
7511 const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex) throw(INTERP_KERNEL::Exception)
7513 if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
7514 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx2 : presence of null pointer in input parameter !");
7515 int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7516 const int *arrIndxInPtr=arrIndxIn->getConstPointer();
7517 const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
7518 int *arrInOutPtr=arrInOut->getPointer();
7519 const int *srcArrPtr=srcArr->getConstPointer();
7520 int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx2 : ");
7522 for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
7524 if(it>=0 && it<nbOfTuples)
7526 if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[it+1]-arrIndxInPtr[it])
7527 std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[it]);
7530 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx2 : On pos #" << i << " id (idsOfSelectBg[" << i << "]) is " << it << " arrIndxIn[id+1]-arrIndxIn[id]!=srcArrIndex[pos+1]-srcArrIndex[pos] !";
7531 throw INTERP_KERNEL::Exception(oss.str().c_str());
7536 std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx2 : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
7537 throw INTERP_KERNEL::Exception(oss.str().c_str());
7543 * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
7544 * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
7545 * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
7546 * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
7547 * The sum of measure field of returned mesh is equal to the sum of measure field of this.
7549 * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
7551 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const throw(INTERP_KERNEL::Exception)
7553 checkFullyDefined();
7554 int mdim=getMeshDimension();
7555 int spaceDim=getSpaceDimension();
7557 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
7558 std::vector<DataArrayInt *> partition=partitionBySpreadZone();
7559 std::vector< MEDCouplingAutoRefCountObjectPtr<DataArrayInt> > partitionAuto; partitionAuto.reserve(partition.size());
7560 std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MEDCouplingAutoRefCountObjectPtr<DataArrayInt> > >(partitionAuto));
7561 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
7562 ret->setCoords(getCoords());
7563 ret->allocateCells((int)partition.size());
7565 for(std::vector<DataArrayInt *>::const_iterator it=partition.begin();it!=partition.end();it++)
7567 MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
7568 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cell;
7572 cell=tmp->buildUnionOf2DMesh();
7575 cell=tmp->buildUnionOf3DMesh();
7578 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
7581 ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->getConstPointer()+1);
7584 ret->finishInsertingCells();
7585 ret->incrRef(); return ret;
7589 * This method partitions \b this into contiguous zone.
7590 * This method only needs a well defined connectivity. Coordinates are not considered here.
7591 * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
7593 std::vector<DataArrayInt *> MEDCouplingUMesh::partitionBySpreadZone() const throw(INTERP_KERNEL::Exception)
7595 int nbOfCellsCur=getNumberOfCells();
7596 DataArrayInt *neigh=0,*neighI=0;
7597 computeNeighborsOfCells(neigh,neighI);
7598 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> neighAuto(neigh),neighIAuto(neighI);
7599 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ids=DataArrayInt::New(); ids->alloc(nbOfCellsCur,1); ids->iota();
7600 std::vector<DataArrayInt *> ret;
7601 std::vector< MEDCouplingAutoRefCountObjectPtr<DataArrayInt> > ret2;
7602 while(nbOfCellsCur>0)
7604 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp=MEDCouplingUMesh::ComputeSpreadZoneGradually(neighAuto,neighIAuto);
7605 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp3=tmp->buildComplement(nbOfCellsCur);
7606 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp2=ids->selectByTupleId(tmp->begin(),tmp->end());
7607 ret2.push_back(tmp2); ret.push_back(tmp2);
7608 nbOfCellsCur=tmp3->getNumberOfTuples();
7611 ids=ids->selectByTupleId(tmp3->begin(),tmp3->end());
7612 MEDCouplingUMesh::ExtractFromIndexedArrays(tmp3->begin(),tmp3->end(),neighAuto,neighIAuto,neigh,neighI);
7615 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> renum=tmp3->invertArrayN2O2O2N(nbOfCellsCur+tmp->getNumberOfTuples());
7616 neighAuto->transformWithIndArr(renum->begin(),renum->end());
7619 for(std::vector<DataArrayInt *>::const_iterator it=ret.begin();it!=ret.end();it++)
7625 * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
7626 * newly allocated DataArrayInt instance with 2 components ready to be interpreted as input of DataArrayInt::findRangeIdForEachTuple method.
7628 * \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.
7629 * \return a newly allocated DataArrayInt to be managed by the caller.
7630 * \throw In case of \a code has not the right format (typically of size 3*n)
7632 DataArrayInt *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<int>& code) throw(INTERP_KERNEL::Exception)
7634 MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret=DataArrayInt::New();
7635 std::size_t nb=code.size()/3;
7636 if(code.size()%3!=0)
7637 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
7638 ret->alloc((int)nb,2);
7639 int *retPtr=ret->getPointer();
7640 for(std::size_t i=0;i<nb;i++,retPtr+=2)
7642 retPtr[0]=code[3*i+2];
7643 retPtr[1]=code[3*i+2]+code[3*i+1];
7649 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
7650 _own_cell(true),_cell_id(-1),_nb_cell(0)
7655 _nb_cell=mesh->getNumberOfCells();
7659 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
7667 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_cell(itc),
7668 _own_cell(false),_cell_id(bg-1),
7675 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
7678 if(_cell_id<_nb_cell)
7687 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
7693 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
7695 return new MEDCouplingUMeshCellByTypeIterator(_mesh);
7698 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
7704 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh, INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_type(type),
7712 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
7718 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
7723 int MEDCouplingUMeshCellEntry::getNumberOfElems() const
7728 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
7730 return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
7733 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
7738 _nb_cell=mesh->getNumberOfCells();
7742 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
7749 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
7751 const int *c=_mesh->getNodalConnectivity()->getConstPointer();
7752 const int *ci=_mesh->getNodalConnectivityIndex()->getConstPointer();
7753 if(_cell_id<_nb_cell)
7755 INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
7756 int nbOfElems=(int)std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,ParaMEDMEMImpl::ConnReader(c,type)));
7757 int startId=_cell_id;
7758 _cell_id+=nbOfElems;
7759 return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
7765 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
7769 _conn=mesh->getNodalConnectivity()->getPointer();
7770 _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
7774 void MEDCouplingUMeshCell::next()
7776 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
7781 _conn_lgth=_conn_indx[1]-_conn_indx[0];
7784 std::string MEDCouplingUMeshCell::repr() const
7786 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
7788 std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
7790 std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<int>(oss," "));
7794 return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
7797 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
7799 if(_conn_lgth!=NOTICABLE_FIRST_VAL)
7800 return (INTERP_KERNEL::NormalizedCellType)_conn[0];
7802 return INTERP_KERNEL::NORM_ERROR;
7805 const int *MEDCouplingUMeshCell::getAllConn(int& lgth) const
7808 if(_conn_lgth!=NOTICABLE_FIRST_VAL)