From: geay Date: Mon, 3 Mar 2014 14:01:22 +0000 (+0100) Subject: addition of MEDCouplingUMesh::conformize2D to conformize a 2D mesh X-Git-Tag: V7_4_0a1~29 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=19d6dd71425b9ea48c69846d9c37cbafdce2b363;p=modules%2Fmed.git addition of MEDCouplingUMesh::conformize2D to conformize a 2D mesh --- diff --git a/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DEdge.cxx b/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DEdge.cxx index 6d2e6ebee..f13b409dd 100644 --- a/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DEdge.cxx +++ b/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DEdge.cxx @@ -876,6 +876,49 @@ inline bool eqpair(const std::pair& p1, const std::pair& subNodes) +{ + Bounds b; + b.prepareForAggregation(); + b.aggregate(getBounds()); + double xBary,yBary; + double dimChar(b.getCaracteristicDim()); + b.getBarycenter(xBary,yBary); + applySimilarity(xBary,yBary,dimChar); + _start->applySimilarity(xBary,yBary,dimChar); + _end->applySimilarity(xBary,yBary,dimChar); + // + std::size_t sz(subNodes.size()),i(0); + std::vector< std::pair > an2(sz); + std::map m; + for(std::vector::const_iterator it=subNodes.begin();it!=subNodes.end();it++,i++) + { + Node *n(new Node(coo[2*(*it)],coo[2*(*it)+1])); + n->applySimilarity(xBary,yBary,dimChar); + m[n]=*it; + an2[i]=std::pair(getCharactValueBtw0And1(*n),n); + } + std::sort(an2.begin(),an2.end()); + // + bool ret(false); + for(i=0;i::const_iterator it2=m.begin();it2!=m.end();it2++) + (*it2).first->decrRef(); + return ret; +} + /** * Sort nodes so that they all lie consecutively on the edge that has been cut. */ diff --git a/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DEdge.hxx b/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DEdge.hxx index 9bc9eff27..4a3805c50 100644 --- a/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DEdge.hxx +++ b/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DEdge.hxx @@ -238,6 +238,7 @@ namespace INTERP_KERNEL virtual double getCurveLength() const = 0; virtual void getBarycenter(double *bary) const = 0; virtual void getBarycenterOfZone(double *bary) const = 0; + virtual void getMiddleOfPoints(const double *p1, const double *p2, double *mid) const = 0; //! Retrieves a point that is owning to this, well placed for IN/OUT detection of this. Typically midlle of this is returned. virtual Node *buildRepresentantOfMySelf() const = 0; //! Given a magnitude specified by sub-type returns if in or not. See getCharactValue method. @@ -264,6 +265,7 @@ namespace INTERP_KERNEL virtual void dumpInXfigFile(std::ostream& stream, bool direction, int resolution, const Bounds& box) const = 0; bool isEqual(const Edge& other) const; public: + bool sortSubNodesAbs(const double *coo, std::vector& subNodes); void sortIdsAbs(const std::vector& addNodes, const std::map& mapp1, const std::map& mapp2, std::vector& edgesThis); virtual void fillGlobalInfoAbs(bool direction, const std::map& mapThis, const std::map& mapOther, int offset1, int offset2, double fact, double baryX, double baryY, std::vector& edgesThis, std::vector& addCoo, std::map mapAddCoo) const = 0; diff --git a/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DEdgeArcCircle.cxx b/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DEdgeArcCircle.cxx index ab736a68b..def67310b 100644 --- a/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DEdgeArcCircle.cxx +++ b/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DEdgeArcCircle.cxx @@ -630,6 +630,21 @@ void EdgeArcCircle::getBarycenterOfZone(double *bary) const +tmp2*(tmp4-tmp3+(tmp3*tmp3*tmp3-tmp4*tmp4*tmp4)/3.)/2.; } +void EdgeArcCircle::getMiddleOfPoints(const double *p1, const double *p2, double *mid) const +{ + double dx1((p1[0]-_center[0])/_radius),dy1((p1[1]-_center[1])/_radius),dx2((p2[0]-_center[0])/_radius),dy2((p2[1]-_center[1])/_radius); + double angle1(GetAbsoluteAngleOfNormalizedVect(dx1,dy1)),angle2(GetAbsoluteAngleOfNormalizedVect(dx2,dy2)); + // + double myDelta1(angle1-_angle0),myDelta2(angle2-_angle0); + if(_angle>0.) + { myDelta1=myDelta1>=0.?myDelta1:myDelta1+2.*M_PI; myDelta2=myDelta2>=0.?myDelta2:myDelta2+2.*M_PI; } + else + { myDelta1=myDelta1<=0.?myDelta1:myDelta1-2.*M_PI; myDelta2=myDelta2<=0.?myDelta2:myDelta2-2.*M_PI; } + //// + mid[0]=_center[0]+_radius*cos(_angle0+(myDelta1+myDelta2)/2.); + mid[1]=_center[1]+_radius*sin(_angle0+(myDelta1+myDelta2)/2.); +} + /*! * Characteristic value used is angle in ]_Pi;Pi[ from axe 0x. */ diff --git a/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DEdgeArcCircle.hxx b/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DEdgeArcCircle.hxx index 29890f587..2732a80f7 100644 --- a/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DEdgeArcCircle.hxx +++ b/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DEdgeArcCircle.hxx @@ -79,6 +79,7 @@ namespace INTERP_KERNEL double getCurveLength() const; void getBarycenter(double *bary) const; void getBarycenterOfZone(double *bary) const; + void getMiddleOfPoints(const double *p1, const double *p2, double *mid) const; bool isIn(double characterVal) const; Node *buildRepresentantOfMySelf() const; bool isLower(double val1, double val2) const; diff --git a/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DEdgeLin.cxx b/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DEdgeLin.cxx index 8adb7dac8..d50a2411c 100644 --- a/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DEdgeLin.cxx +++ b/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DEdgeLin.cxx @@ -273,6 +273,15 @@ void EdgeLin::getBarycenterOfZone(double *bary) const bary[1]=(x1-x2)*(y1*(y1+y2)+y2*y2)/6.; } +/*! + * Here \a this is not used (contrary to EdgeArcCircle class). + */ +void EdgeLin::getMiddleOfPoints(const double *p1, const double *p2, double *mid) const +{ + mid[0]=(p1[0]+p2[0])/2.; + mid[1]=(p1[1]+p2[1])/2.; +} + double EdgeLin::getCurveLength() const { double x=(*_start)[0]-(*_end)[0]; diff --git a/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DEdgeLin.hxx b/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DEdgeLin.hxx index 6feb7aaf1..6b59aeb92 100644 --- a/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DEdgeLin.hxx +++ b/src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DEdgeLin.hxx @@ -61,6 +61,7 @@ namespace INTERP_KERNEL double getCurveLength() const; void getBarycenter(double *bary) const; void getBarycenterOfZone(double *bary) const; + void getMiddleOfPoints(const double *p1, const double *p2, double *mid) const; bool isIn(double characterVal) const; Node *buildRepresentantOfMySelf() const; double getCharactValue(const Node& node) const; diff --git a/src/MEDCoupling/MEDCouplingField.hxx b/src/MEDCoupling/MEDCouplingField.hxx index ad82ed2cf..d0f408d1a 100644 --- a/src/MEDCoupling/MEDCouplingField.hxx +++ b/src/MEDCoupling/MEDCouplingField.hxx @@ -53,6 +53,7 @@ namespace ParaMEDMEM MEDCOUPLING_EXPORT virtual void copyTinyStringsFrom(const MEDCouplingField *other); MEDCOUPLING_EXPORT void setMesh(const ParaMEDMEM::MEDCouplingMesh *mesh); MEDCOUPLING_EXPORT const ParaMEDMEM::MEDCouplingMesh *getMesh() const { return _mesh; } + MEDCOUPLING_EXPORT ParaMEDMEM::MEDCouplingMesh *getMesh() { return const_cast(_mesh); } MEDCOUPLING_EXPORT void setName(const std::string& name) { _name=name; } MEDCOUPLING_EXPORT std::string getDescription() const { return _desc; } MEDCOUPLING_EXPORT void setDescription(const std::string& desc) { _desc=desc; } diff --git a/src/MEDCoupling/MEDCouplingFieldDouble.cxx b/src/MEDCoupling/MEDCouplingFieldDouble.cxx index 4f14393c4..0390442b0 100644 --- a/src/MEDCoupling/MEDCouplingFieldDouble.cxx +++ b/src/MEDCoupling/MEDCouplingFieldDouble.cxx @@ -2115,7 +2115,7 @@ void MEDCouplingFieldDouble::changeUnderlyingMesh(const MEDCouplingMesh *other, renumberCellsWithoutMesh(cellCor->getConstPointer(),false); if(nodeCor) renumberNodesWithoutMesh(nodeCor->getConstPointer(),nodeCor->getMaxValueInArray()+1,eps); - setMesh(const_cast(other)); + setMesh(other); } /*! diff --git a/src/MEDCoupling/MEDCouplingMemArray.cxx b/src/MEDCoupling/MEDCouplingMemArray.cxx index c749ff93c..7f1d76989 100644 --- a/src/MEDCoupling/MEDCouplingMemArray.cxx +++ b/src/MEDCoupling/MEDCouplingMemArray.cxx @@ -9564,12 +9564,35 @@ DataArrayInt *DataArrayInt::BuildIntersection(const std::vectoralloc((int)r.size(),1); std::copy(r.begin(),r.end(),ret->getPointer()); return ret; } +/*! + * This method allows to put a vector of vector of integer into a more compact data stucture (skyline). + * This method is not available into python because no available optimized data structure available to map std::vector< std::vector >. + * + * \param [in] v the input data structure to be translate into skyline format. + * \param [out] data the first element of the skyline format. The user is expected to deal with newly allocated array. + * \param [out] dataIndex the second element of the skyline format. + */ +void DataArrayInt::PutIntoToSkylineFrmt(const std::vector< std::vector >& v, DataArrayInt *& data, DataArrayInt *& dataIndex) +{ + int sz((int)v.size()); + MEDCouplingAutoRefCountObjectPtr ret0(DataArrayInt::New()),ret1(DataArrayInt::New()); + ret1->alloc(sz+1,1); + int *pt(ret1->getPointer()); *pt=0; + for(int i=0;ialloc(ret1->back(),1); + pt=ret0->getPointer(); + for(int i=0;i& groups, int newNb, std::vector< std::vector >& fidsOfGroups); MEDCOUPLING_EXPORT static DataArrayInt *BuildUnion(const std::vector& arr); MEDCOUPLING_EXPORT static DataArrayInt *BuildIntersection(const std::vector& arr); + MEDCOUPLING_EXPORT static void PutIntoToSkylineFrmt(const std::vector< std::vector >& v, DataArrayInt *& data, DataArrayInt *& dataIndex); MEDCOUPLING_EXPORT DataArrayInt *buildComplement(int nbOfElement) const; MEDCOUPLING_EXPORT DataArrayInt *buildSubstraction(const DataArrayInt *other) const; MEDCOUPLING_EXPORT DataArrayInt *buildSubstractionOptimized(const DataArrayInt *other) const; diff --git a/src/MEDCoupling/MEDCouplingUMesh.cxx b/src/MEDCoupling/MEDCouplingUMesh.cxx index 2d46d5cfa..70713386c 100644 --- a/src/MEDCoupling/MEDCouplingUMesh.cxx +++ b/src/MEDCoupling/MEDCouplingUMesh.cxx @@ -4090,6 +4090,41 @@ namespace ParaMEDMEM INTERP_KERNEL::NormalizedCellType getTypeOfElement(int) const { return (INTERP_KERNEL::NormalizedCellType)0; } // end }; + + /*! + * Warning the nodes in \a m should be decrRefed ! To avoid that Node * pointer be replaced by another instance. + */ + INTERP_KERNEL::Edge *MEDCouplingUMeshBuildQPFromEdge2(INTERP_KERNEL::NormalizedCellType typ, const int *bg, const double *coords2D, std::map& m) + { + INTERP_KERNEL::Edge *ret=0; + INTERP_KERNEL::Node *n0(new INTERP_KERNEL::Node(coords2D[2*bg[0]],coords2D[2*bg[0]+1])),*n1(new INTERP_KERNEL::Node(coords2D[2*bg[1]],coords2D[2*bg[1]+1])); + m[n0]=bg[0]; m[n1]=bg[1]; + switch(typ) + { + case INTERP_KERNEL::NORM_SEG2: + { + ret=new INTERP_KERNEL::EdgeLin(n0,n1); + break; + } + case INTERP_KERNEL::NORM_SEG3: + { + INTERP_KERNEL::Node *n2(new INTERP_KERNEL::Node(coords2D[2*bg[2]],coords2D[2*bg[2]+1])); m[n2]=bg[2]; + INTERP_KERNEL::EdgeLin *e1(new INTERP_KERNEL::EdgeLin(n0,n2)),*e2(new INTERP_KERNEL::EdgeLin(n2,n1)); + INTERP_KERNEL::SegSegIntersector inters(*e1,*e2); + // is the SEG3 degenerated, and thus can be reduced to a SEG2? + bool colinearity(inters.areColinears()); + delete e1; delete e2; + if(colinearity) + { ret=new INTERP_KERNEL::EdgeLin(n0,n1); } + else + { ret=new INTERP_KERNEL::EdgeArcCircle(n0,n2,n1); } + break; + } + default: + throw INTERP_KERNEL::Exception("MEDCouplingUMeshBuildQPFromEdge2 : Expecting a mesh with spaceDim==2 and meshDim==1 !"); + } + return ret; + } INTERP_KERNEL::Edge *MEDCouplingUMeshBuildQPFromEdge(INTERP_KERNEL::NormalizedCellType typ, std::map >& mapp2, const int *bg) { @@ -8698,6 +8733,208 @@ void MEDCouplingUMesh::BuildIntersecting2DCellsFromEdges(double eps, const MEDCo } } +void IKGeo2DInternalMapper2(INTERP_KERNEL::Node *n, const std::map& m, int forbVal0, int forbVal1, std::vector& isect) +{ + std::map::const_iterator it(m.find(n)); + if(it==m.end()) + throw INTERP_KERNEL::Exception("Internal error in remapping !"); + int v((*it).second); + if(v==forbVal0 || v==forbVal1) + return ; + if(std::find(isect.begin(),isect.end(),v)==isect.end()) + isect.push_back(v); +} + +bool IKGeo2DInternalMapper(const INTERP_KERNEL::ComposedEdge& c, const std::map& m, int forbVal0, int forbVal1, std::vector& isect) +{ + int sz(c.size()); + if(sz<=1) + return false; + bool presenceOfOn(false); + for(int i=0;igetLoc()!=INTERP_KERNEL::FULL_ON_1) + continue ; + IKGeo2DInternalMapper2(e->getStartNode(),m,forbVal0,forbVal1,isect); + IKGeo2DInternalMapper2(e->getEndNode(),m,forbVal0,forbVal1,isect); + } + return presenceOfOn; +} + +/** + * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg and in \a subNodesInSegI using index storage mode. + * To do the work this method can optionnaly needs information about middle of subedges for quadratic cases if a minimal creation of new nodes is wanted. + * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add nodes if a SEG3 is split without information of middle. + * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to avoid to have a non conform mesh. + * + * \return int - the number of new nodes created (in most of cases 0). + * + * \throw If \a this is not coherent. + * \throw If \a this has not spaceDim equal to 2. + * \throw If \a this has not meshDim equal to 2. + * \throw If some subcells needed to be split are orphan. + * \sa MEDCouplingUMesh::conformize2D + */ +int MEDCouplingUMesh::split2DCells(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *midOpt, const DataArrayInt *midOptI) +{ + if(!desc || !descI || !subNodesInSeg || !subNodesInSegI) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !"); + desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated(); + if(getSpaceDimension()!=2 || getMeshDimension()!=2) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !"); + if(midOpt==0 && midOptI==0) + { + split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI); + return 0; + } + else if(midOpt!=0 && midOptI!=0) + return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI); + else + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all."); +} + +/*! + * \b WARNING this method is \b potentially \b non \b const (if returned array is empty). + * \b WARNING this method lead to have a non geometric type sorted mesh (for MED file users) ! + * This method performs a conformization of \b this. So if a edge in \a this can be split into entire edges in \a this this method + * will suppress such edges to use sub edges in \a this. So this method does not add nodes in \a this if merged edges have same nature each other (Linear,Quadratic). + * Whatever the returned value, this method does not alter the order of cells in \a this neither the orientation of cells. + * The modified cells if any are systematically declared as NORM_POLYGON or NORM_QPOLYG depending on the + * + * This method expects that \b this has a meshDim equal 2 and spaceDim equal to 2 too. + * This method expects that all nodes in \a this are not closer than \a eps. + * If it is not the case you can invoke MEDCouplingUMesh::mergeNodes before calling this method. + * + * \param [in] eps the relative error to detect merged edges. + * \return DataArrayInt * - The list of cellIds in \a this that have been subdivided. If empty, nothing changed in \a this (as if it were a const method). The array is a newly allocated array + * that the user is expected to deal with. + * + * \throw If \a this is not coherent. + * \throw If \a this has not spaceDim equal to 2. + * \throw If \a this has not meshDim equal to 2. + * \sa MEDCouplingUMesh::mergeNodes, MEDCouplingUMesh::split2DCells + */ +DataArrayInt *MEDCouplingUMesh::conformize2D(double eps) +{ + static const int SPACEDIM=2; + checkCoherency(); + if(getSpaceDimension()!=2 || getMeshDimension()!=2) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::conformize2D : This method only works for meshes with spaceDim=2 and meshDim=2 !"); + MEDCouplingAutoRefCountObjectPtr desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New()); + MEDCouplingAutoRefCountObjectPtr mDesc(buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1)); + const int *c(mDesc->getNodalConnectivity()->getConstPointer()),*ci(mDesc->getNodalConnectivityIndex()->getConstPointer()),*rd(revDesc1->getConstPointer()),*rdi(revDescIndx1->getConstPointer()); + MEDCouplingAutoRefCountObjectPtr bboxArr(mDesc->getBoundingBoxForBBTree()); + const double *bbox(bboxArr->begin()),*coords(getCoords()->begin()); + int nCell(getNumberOfCells()),nDescCell(mDesc->getNumberOfCells()); + std::vector< std::vector > intersectEdge(nDescCell),overlapEdge(nDescCell); + std::vector addCoo; + BBTree myTree(bbox,0,0,nDescCell,-eps); + INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps; + INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps; + for(int i=0;i candidates; + myTree.getIntersectingElems(bbox+i*2*SPACEDIM,candidates); + for(std::vector::const_iterator it=candidates.begin();it!=candidates.end();it++) + if(*it>i) + { + std::map m; + INTERP_KERNEL::Edge *e1(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coords,m)), + *e2(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[*it]],c+ci[*it]+1,coords,m)); + INTERP_KERNEL::MergePoints merge; + INTERP_KERNEL::QuadraticPolygon c1,c2; + e1->intersectWith(e2,merge,c1,c2); + e1->decrRef(); e2->decrRef(); + if(IKGeo2DInternalMapper(c1,m,c[ci[i]+1],c[ci[i]+2],intersectEdge[i])) + overlapEdge[i].push_back(*it); + if(IKGeo2DInternalMapper(c2,m,c[ci[*it]+1],c[ci[*it]+2],intersectEdge[*it])) + overlapEdge[*it].push_back(i); + for(std::map::const_iterator it2=m.begin();it2!=m.end();it2++) + (*it2).first->decrRef(); + } + } + // splitting done. sort intersect point in intersectEdge. + std::vector< std::vector > middle(nDescCell); + int nbOf2DCellsToBeSplit(0); + bool middleNeedsToBeUsed(false); + std::vector cells2DToTreat(nDescCell,false); + for(int i=0;i& isect(intersectEdge[i]); + int sz((int)isect.size()); + if(sz>1) + { + std::map m; + INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coords,m)); + e->sortSubNodesAbs(coords,isect); + e->decrRef(); + for(std::map::const_iterator it2=m.begin();it2!=m.end();it2++) + (*it2).first->decrRef(); + } + if(sz!=0) + { + int idx0(rdi[i]),idx1(rdi[i+1]); + if(idx1-idx0!=1) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::conformize2D : internal error #0 !"); + if(!cells2DToTreat[rd[idx0]]) + { + cells2DToTreat[rd[idx0]]=true; + nbOf2DCellsToBeSplit++; + } + // try to reuse at most eventual 'middle' of SEG3 + std::vector& mid(middle[i]); + mid.resize(sz+1,-1); + if((INTERP_KERNEL::NormalizedCellType)c[ci[i]]==INTERP_KERNEL::NORM_SEG3) + { + middleNeedsToBeUsed=true; + const std::vector& candidates(overlapEdge[i]); + std::vector trueCandidates; + for(std::vector::const_iterator itc=candidates.begin();itc!=candidates.end();itc++) + if((INTERP_KERNEL::NormalizedCellType)c[ci[*itc]]==INTERP_KERNEL::NORM_SEG3) + trueCandidates.push_back(*itc); + int stNode(c[ci[i]+1]),endNode(isect[0]); + for(int j=0;j::const_iterator itc=trueCandidates.begin();itc!=trueCandidates.end();itc++) + { + int tmpSt(c[ci[*itc]+1]),tmpEnd(c[ci[*itc]+2]); + if((tmpSt==stNode && tmpEnd==endNode) || (tmpSt==endNode && tmpEnd==stNode)) + { mid[j]=*itc; break; } + } + stNode=endNode; + endNode=j ret(DataArrayInt::New()),notRet(DataArrayInt::New()); ret->alloc(nbOf2DCellsToBeSplit,1); + if(nbOf2DCellsToBeSplit==0) + return ret.retn(); + // + int *retPtr(ret->getPointer()); + for(int i=0;i mSafe,nSafe,oSafe,pSafe,qSafe,rSafe; + DataArrayInt *m(0),*n(0),*o(0),*p(0),*q(0),*r(0); + MEDCouplingUMesh::ExtractFromIndexedArrays(ret->begin(),ret->end(),desc1,descIndx1,m,n); mSafe=m; nSafe=n; + DataArrayInt::PutIntoToSkylineFrmt(intersectEdge,o,p); oSafe=o; pSafe=p; + if(middleNeedsToBeUsed) + { DataArrayInt::PutIntoToSkylineFrmt(middle,q,r); qSafe=q; rSafe=r; } + MEDCouplingAutoRefCountObjectPtr modif(static_cast(buildPartOfMySelf(ret->begin(),ret->end(),true))); + int nbOfNodesCreated(modif->split2DCells(mSafe,nSafe,oSafe,pSafe,qSafe,rSafe)); + setCoords(modif->getCoords());//if nbOfNodesCreated==0 modif and this have the same coordinates pointer so this line has no effect. But for quadratic cases this line is important. + setPartOfMySelf(ret->begin(),ret->end(),*modif); + { + bool areNodesMerged; int newNbOfNodes; + if(nbOfNodesCreated!=0) + MEDCouplingAutoRefCountObjectPtr tmp(mergeNodes(eps,areNodesMerged,newNbOfNodes)); + } + return ret.retn(); +} + /*! * This method is private and is the first step of Partition of 2D mesh (spaceDim==2 and meshDim==2). * It builds the descending connectivity of the two meshes, and then using a binary tree @@ -9771,6 +10008,116 @@ MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayInt *& return ret0.retn(); } +/*! + * It is the linear part of MEDCouplingUMesh::split2DCells. Here no additionnal nodes will be added in \b this. So coordinates pointer remain unchanged (is not even touch). + * + * \sa MEDCouplingUMesh::split2DCells + */ +void MEDCouplingUMesh::split2DCellsLinear(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI) +{ + checkConnectivityFullyDefined(); + int ncells(getNumberOfCells()),lgthToReach(getMeshLength()+subNodesInSeg->getNumberOfTuples()); + MEDCouplingAutoRefCountObjectPtr c(DataArrayInt::New()); c->alloc((std::size_t)lgthToReach); + const int *subPtr(subNodesInSeg->begin()),*subIPtr(subNodesInSegI->begin()),*descPtr(desc->begin()),*descIPtr(descI->begin()),*oldConn(getNodalConnectivity()->begin()); + int *cPtr(c->getPointer()),*ciPtr(getNodalConnectivityIndex()->getPointer()); + int prevPosOfCi(ciPtr[0]); + for(int i=0;iend()!=cPtr) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCellsLinear : Some of edges to be split are orphan !"); + _nodal_connec->decrRef(); + _nodal_connec=c.retn(); _types.clear(); _types.insert(INTERP_KERNEL::NORM_POLYGON); +} + +int internalAddPoint(const INTERP_KERNEL::Edge *e, int id, const double *coo, int startId, int endId, DataArrayDouble& addCoo, int& nodesCnter) +{ + if(id!=-1) + return id; + else + { + int ret(nodesCnter++); + double newPt[2]; + e->getMiddleOfPoints(coo+2*startId,coo+2*endId,newPt); + addCoo.insertAtTheEnd(newPt,newPt+2); + return ret; + } +} + +/*! + * It is the quadratic part of MEDCouplingUMesh::split2DCells. Here some additionnal nodes can be added at the end of coordinates array object. + * + * \return int - the number of new nodes created. + * \sa MEDCouplingUMesh::split2DCells + */ +int MEDCouplingUMesh::split2DCellsQuadratic(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *mid, const DataArrayInt *midI) +{ + checkCoherency(); + int ncells(getNumberOfCells()),lgthToReach(getMeshLength()+2*subNodesInSeg->getNumberOfTuples()),nodesCnt(getNumberOfNodes()); + MEDCouplingAutoRefCountObjectPtr c(DataArrayInt::New()); c->alloc((std::size_t)lgthToReach); + MEDCouplingAutoRefCountObjectPtr addCoo(DataArrayDouble::New()); addCoo->alloc(0,1); + const int *subPtr(subNodesInSeg->begin()),*subIPtr(subNodesInSegI->begin()),*descPtr(desc->begin()),*descIPtr(descI->begin()),*oldConn(getNodalConnectivity()->begin()); + const int *midPtr(mid->begin()),*midIPtr(midI->begin()); + const double *oldCoordsPtr(getCoords()->begin()); + int *cPtr(c->getPointer()),*ciPtr(getNodalConnectivityIndex()->getPointer()); + int prevPosOfCi(ciPtr[0]); + for(int i=0;i ns(3); + ns[0]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+j]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+j]+1]); + ns[1]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+(1+j)%sz]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+(1+j)%sz]+1]); + ns[2]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+sz+j]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+sz+j]+1]); + MEDCouplingAutoRefCountObjectPtr e(INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(ns)); + for(int k=0;kend()!=cPtr) + throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCellsQuadratic : Some of edges to be split are orphan !"); + _nodal_connec->decrRef(); + _nodal_connec=c.retn(); _types.clear(); _types.insert(INTERP_KERNEL::NORM_QPOLYG); + addCoo->rearrange(2); + MEDCouplingAutoRefCountObjectPtr coo(DataArrayDouble::Aggregate(getCoords(),addCoo));//info are copied from getCoords() by using Aggregate + setCoords(coo); + return addCoo->getNumberOfTuples(); +} + MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)), _own_cell(true),_cell_id(-1),_nb_cell(0) { diff --git a/src/MEDCoupling/MEDCouplingUMesh.hxx b/src/MEDCoupling/MEDCouplingUMesh.hxx index df10fbb49..06d472ef9 100644 --- a/src/MEDCoupling/MEDCouplingUMesh.hxx +++ b/src/MEDCoupling/MEDCouplingUMesh.hxx @@ -219,6 +219,8 @@ namespace ParaMEDMEM MEDCOUPLING_EXPORT DataArrayDouble *computeIsoBarycenterOfNodesPerCell() const; MEDCOUPLING_EXPORT DataArrayDouble *getPartBarycenterAndOwner(const int *begin, const int *end) const; MEDCOUPLING_EXPORT DataArrayDouble *computePlaneEquationOf3DFaces() const; + MEDCOUPLING_EXPORT DataArrayInt *conformize2D(double eps); + MEDCOUPLING_EXPORT int split2DCells(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *midOpt=0, const DataArrayInt *midOptI=0); MEDCOUPLING_EXPORT static MEDCouplingUMesh *Build0DMeshFromCoords(DataArrayDouble *da); MEDCOUPLING_EXPORT static MEDCouplingUMesh *MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2); MEDCOUPLING_EXPORT static MEDCouplingUMesh *MergeUMeshes(std::vector& a); @@ -319,6 +321,8 @@ namespace ParaMEDMEM const int *desc, const int *descIndx, std::vector< std::pair >& cut3DSurf) throw(INTERP_KERNEL::Exception); void assemblyForSplitFrom3DSurf(const std::vector< std::pair >& cut3DSurf, const int *desc, const int *descIndx, DataArrayInt *nodalRes, DataArrayInt *nodalResIndx, DataArrayInt *cellIds) const throw(INTERP_KERNEL::Exception); + void split2DCellsLinear(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI); + int split2DCellsQuadratic(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *mid, const DataArrayInt *midI); public: MEDCOUPLING_EXPORT static DataArrayInt *ComputeRangesFromTypeDistribution(const std::vector& code); MEDCOUPLING_EXPORT static const int N_MEDMEM_ORDER=24; diff --git a/src/MEDCoupling_Swig/MEDCouplingBasicsTest.py b/src/MEDCoupling_Swig/MEDCouplingBasicsTest.py index 8435e49a5..2af096bf8 100644 --- a/src/MEDCoupling_Swig/MEDCouplingBasicsTest.py +++ b/src/MEDCoupling_Swig/MEDCouplingBasicsTest.py @@ -14283,6 +14283,102 @@ class MEDCouplingBasicsTest(unittest.TestCase): self.assertTrue(p.getCoords().isEqual(DataArrayDouble([0.,0.,1.,0.,2.,0.,3.,0.,4.,0.,5.,0.,0.,1.,1.,1.,2.,1.,3.,1.,4.,1.,5.,1.,0.,2.,1.,2.,2.,2.,3.,2.,4.,2.,5.,2.,0.,3.,1.,3.,2.,3.,3.,3.,4.,3.,5.,3.,0.,4.,1.,4.,2.,4.,3.,4.,4.,4.,5.,4.,0.,5.,1.,5.,2.,5.,3.,5.,4.,5.,5.,5.,0.5,0.,0.,0.5,0.5,1.,1.,0.5,1.5,0.,1.5,1.,2.,0.5,2.5,0.,2.5,1.,3.,0.5,3.5,0.,3.5,1.,4.,0.5,4.5,0.,4.5,1.,5.,0.5,1.,1.5,1.5,2.,2.,1.5,2.5,2.,3.,1.5,3.5,2.,4.,1.5,4.5,2.,5.,1.5,0.5,2.,0.,2.5,0.5,3.,1.,2.5,2.,2.5,2.5,3.,3.,2.5,3.5,3.,4.,2.5,4.5,3.,5.,2.5,0.,3.5,0.5,4.,1.,3.5,1.5,3.,1.5,4.,2.,3.5,3.,3.5,3.5,4.,4.,3.5,4.5,4.,5.,3.5,0.,4.5,0.5,5.,1.,4.5,1.5,5.,2.,4.5,2.5,4.,2.5,5.,3.,4.5,4.,4.5,4.5,5.,5.,4.5,0.,1.5,0.5,1.5,1.5,2.5,2.5,3.5,3.5,4.5,3.5,5.0],100,2),1e-13)) pass + def testSwig2Conformize2D1(self): + eps = 1.0e-8 + coo = [0.,-0.5,0.,0.,0.5,0.,0.5,-0.5,0.25, + -0.1,0.25,0.,0.5,-0.1,0.,0.5,0.5,0.5,0.25,0.4,0.25,0.5,0.5,0.4] + conn = [5,5,2,6,4,5,6,3,0,1,5,4,5,10,8,11,9,5,11,2,1,7,10,9] + connI = [0,5,12,17,24] + m = MEDCouplingUMesh("box",2) + cooArr = DataArrayDouble(coo,len(coo)/2,2) + m.setCoords(cooArr) + m.setConnectivity(DataArrayInt(conn),DataArrayInt(connI)) + m.mergeNodes(eps) + m.checkCoherency() + self.assertTrue(m.conformize2D(eps).isEqual(DataArrayInt([3]))) + self.assertEqual(m.getCoords().getHiddenCppPointer(),cooArr.getHiddenCppPointer()) # check that coordinates remain the same here + self.assertTrue(m.getNodalConnectivity().isEqual(DataArrayInt([5,5,2,6,4,5,6,3,0,1,5,4,5,10,8,11,9,5,11,2,5,1,7,10,9]))) + self.assertTrue(m.getNodalConnectivityIndex().isEqual(DataArrayInt([0,5,12,17,25]))) + pass + + def testSwig2Conformize2D2(self): + eps = 1.0e-8 + coo=DataArrayDouble([-10,-6,0,-6,0,0,7,0,-10,2,0,2,0,6,7,6,0,8,7,8,-10,12,-4,12,0,12,0,11,7,11,-4,16,0,16,7,16],18,2) + conn=DataArrayInt([2,3,7,6, 13,16,17,14, 4,10,12,5, 9,14,13,8, 8,9,7,6, 5,4,0,1, 16,12,11,15]) + m=MEDCoupling1SGTUMesh("mesh",NORM_QUAD4) + m.setCoords(coo) + m.setNodalConnectivity(conn) + m=m.buildUnstructured() + self.assertTrue(m.conformize2D(eps).isEqual(DataArrayInt([0,1,2,5]))) + self.assertEqual(m.getCoords().getHiddenCppPointer(),coo.getHiddenCppPointer()) # check that coordinates remain the same here + self.assertTrue(m.getNodalConnectivity().isEqual(DataArrayInt([5,2,3,7,6,5, 5,13,12,16,17,14, 5,4,10,11,12,13,8,6,5, 4,9,14,13,8, 4,8,9,7,6, 5,5,4,0,1,2, 4,16,12,11,15]))) + self.assertTrue(m.getNodalConnectivityIndex().isEqual(DataArrayInt([0,6,12,21,26,31,37,42]))) + pass + + def testSwigSplit2DCells1(self): + coo=DataArrayDouble([[0,0],[1,0],[1,1],[0,1],[0.5,0],[1,0.5],[0.5,1],[0.,0.5]]) + m=MEDCouplingUMesh("mesh",2) + m.setCoords(coo) + m.allocateCells() + m.insertNextCell(NORM_QUAD8,[0,1,2,3,4,5,6,7]) + _,d,di,_,_=m.buildDescendingConnectivity() + subb=DataArrayInt([5]) + subbi=DataArrayInt([0,0,1,1,1]) + mid=DataArrayInt([-1,-1]) + midi=DataArrayInt([0,0,2,2,2]) + self.assertEqual(2,m.split2DCells(d,di,subb,subbi,mid,midi)) + self.assertTrue(m.getNodalConnectivity().isEqual(DataArrayInt([32,0,1,5,2,3,4,8,9,6,7]))) + self.assertTrue(m.getNodalConnectivityIndex().isEqual(DataArrayInt([0,11]))) + self.assertTrue(m.getCoords().isEqual(DataArrayDouble([[0,0],[1,0],[1,1],[0,1],[0.5,0],[1,0.5],[0.5,1],[0.,0.5],[1.,0.25],[1.,0.75]]),1e-12)) + pass + + def testSwig2Conformize2D3(self): + eps = 1.0e-8 + coo=DataArrayDouble([-10,-6,0,-6,0,0,7,0,-10,2,0,2,0,6.5,7,6.5,0,8,7,8,-10,12,-4,12,0,12,0,11,7,11,-4,16,0,16,7,16],18,2) + conn=DataArrayInt([2,3,7,6, 13,16,17,14, 4,10,12,5, 9,14,13,8, 8,9,7,6, 5,4,0,1, 16,12,11,15]) + m=MEDCoupling1SGTUMesh("mesh",NORM_QUAD4) + m.setCoords(coo) + m.setNodalConnectivity(conn) + m=m.buildUnstructured() + m.convertLinearCellsToQuadratic() + self.assertTrue(m.conformize2D(eps).isEqual(DataArrayInt([0,1,2,5]))) + self.assertTrue(m.getCoords().getHiddenCppPointer()!=coo.getHiddenCppPointer()) # coordinates are not the same here contrary to testSwig2Conformize2D2 ... + self.assertTrue(m.getCoords()[:18].isEqual(coo,1e-12)) # but the 18 first nodes are the same + pass + + def testSwig2Conformize2D4(self): + eps = 1.0e-8 + coo=DataArrayDouble([-10,-6,0,-6,0,0,7,0,-10,2,0,2,0,6.5,7,6.5,0,8,7,8,-10,12,-4,12,0,12,0,11,7,11,-4,16,0,16,7,16],18,2) + conn=DataArrayInt([2,3,7,6, 13,16,17,14, 4,10,12,5, 9,14,13,8, 8,9,7,6, 5,4,0,1, 16,12,11,15]) + m=MEDCoupling1SGTUMesh("mesh",NORM_QUAD4) + m.setCoords(coo) + m.setNodalConnectivity(conn) + m=m.buildUnstructured() + m.convertLinearCellsToQuadratic() + self.assertEqual(42,m.getNumberOfNodes()) + oldCoo=m.getCoords().deepCpy() + m.conformize2D(eps) + self.assertTrue(m.getCoords()[:42].isEqual(oldCoo,1e-12)) + self.assertTrue(m.getNodalConnectivity().isEqual(DataArrayInt([32,2,3,7,6,5,18,19,20,42,43,32,13,12,16,17,14,44,38,23,24,25,32,4,10,11,12,13,8,6,5,26,45,39,44,31,34,42,29,8,9,14,13,8,30,25,31,32,8,8,9,7,6,32,33,20,34,32,5,4,0,1,2,29,35,36,46,43,8,16,12,11,15,38,39,40,41]))) + self.assertTrue(m.getNodalConnectivityIndex().isEqual(DataArrayInt([0,11,22,39,48,57,68,77]))) + self.assertTrue(m.getCoords().isEqual(DataArrayDouble([[-10.,-6.0],[0.,-6.0],[0.,0.0],[7.,0.0],[-10.,2.0],[0.,2.0],[0.,6.5],[7.,6.5],[0.,8.0],[7.,8.0],[-10.,12.0],[-4.,12.0],[0.,12.0],[0.,11.0],[7.,11.0],[-4.,16.0],[0.,16.0],[7.,16.0],[3.5, 0.0],[7.,3.25],[3.5, 6.5],[0.,3.25],[0.,13.5],[3.5, 16.0],[7.,13.5],[3.5, 11.0],[-10.,7.0],[-5.,12.0],[0.,7.0],[-5.,2.0],[7.,9.5],[0.,9.5],[3.5, 8.0],[7.,7.25],[0.,7.25],[-10.,-2.0],[-5.,-6.0],[0.,-2.0],[0.,14.0],[-2.,12.0],[-4.,14.0],[-2.,16.0],[0.,4.25],[0.,1.0],[0.,11.5],[-7.,12.0],[0.,-3.]]),1e-12)) + pass + + def testSwig2Conformize2D5(self): + eps=1e-8 + coo=DataArrayDouble([[2,2],[2,-6],[10,-2],[-2,-2],[6,0],[6,-4],[2,7],[2,4.5],[-1.4641016151377544,0],[-1.950753362380551,-1.3742621398390762],[-7,-3],[-0.8284271247461898,-4.82842712474619],[0.26794919243112281,3.5],[0,1.4641016151377548],[-4.4753766811902755,-2.1871310699195381],[-3.9142135623730949,-3.9142135623730949],[-1.8042260651806146,-3.23606797749979]]) + m=MEDCouplingUMesh("mesh",2) + m.allocateCells() + m.setCoords(coo) + m.insertNextCell(NORM_TRI6,[1,2,0,5,4,3]) + m.insertNextCell(NORM_TRI6,[8,6,0,12,7,13]) + m.insertNextCell(NORM_TRI6,[11,9,10,16,14,15]) + self.assertTrue(m.conformize2D(eps).isEqual(DataArrayInt([0]))) + self.assertTrue(m.getCoords().isEqual(DataArrayDouble([2.,2.,2.,-6.,10.,-2.,-2.,-2.,6.,0.,6.,-4.,2.,7.,2.,4.5,-1.4641016151377544,0.,-1.950753362380551,-1.3742621398390762,-7.,-3.,-0.8284271247461898,-4.82842712474619,0.2679491924311228,3.5,8.881784197001252e-16,1.4641016151377548,-4.4753766811902755,-2.187131069919538,-3.914213562373095,-3.914213562373095,-1.8042260651806146,-3.236067977499789,-1.7705659643687133,-0.6647725630649153,0.46926627053963865,-5.695518130045146],19,2),1e-12)) + self.assertTrue(m.getNodalConnectivity().isEqual(DataArrayInt([32,1,2,0,8,9,11,5,4,13,17,16,18,6,8,6,0,12,7,13,6,11,9,10,16,14,15]))) + self.assertTrue(m.getNodalConnectivityIndex().isEqual(DataArrayInt([0,13,20,27]))) + pass + def setUp(self): pass pass diff --git a/src/MEDCoupling_Swig/MEDCouplingCommon.i b/src/MEDCoupling_Swig/MEDCouplingCommon.i index 10f11f7fb..b9d0854f2 100644 --- a/src/MEDCoupling_Swig/MEDCouplingCommon.i +++ b/src/MEDCoupling_Swig/MEDCouplingCommon.i @@ -238,6 +238,7 @@ using namespace INTERP_KERNEL; %newobject ParaMEDMEM::MEDCouplingUMesh::ComputeSpreadZoneGradually; %newobject ParaMEDMEM::MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed; %newobject ParaMEDMEM::MEDCouplingUMesh::buildNewNumberingFromCommNodesFrmt; +%newobject ParaMEDMEM::MEDCouplingUMesh::conformize2D; %newobject ParaMEDMEM::MEDCouplingUMesh::rearrange2ConsecutiveCellTypes; %newobject ParaMEDMEM::MEDCouplingUMesh::sortCellsInMEDFileFrmt; %newobject ParaMEDMEM::MEDCouplingUMesh::getRenumArrForMEDFileFrmt; @@ -1501,6 +1502,7 @@ namespace ParaMEDMEM std::string reprConnectivityOfThis() const throw(INTERP_KERNEL::Exception); MEDCouplingUMesh *buildSetInstanceFromThis(int spaceDim) const throw(INTERP_KERNEL::Exception); //tools + DataArrayInt *conformize2D(double eps) throw(INTERP_KERNEL::Exception); void shiftNodeNumbersInConn(int delta) throw(INTERP_KERNEL::Exception); std::vector getQuadraticStatus() const throw(INTERP_KERNEL::Exception); DataArrayInt *findCellIdsOnBoundary() const throw(INTERP_KERNEL::Exception); @@ -1542,6 +1544,7 @@ namespace ParaMEDMEM DataArrayDouble *getBoundingBoxForBBTreeFast() const throw(INTERP_KERNEL::Exception); DataArrayDouble *getBoundingBoxForBBTree2DQuadratic(double arcDetEps=1e-12) const throw(INTERP_KERNEL::Exception); DataArrayDouble *getBoundingBoxForBBTree1DQuadratic(double arcDetEps=1e-12) const throw(INTERP_KERNEL::Exception); + int split2DCells(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *midOpt=0, const DataArrayInt *midOptI=0) throw(INTERP_KERNEL::Exception); static MEDCouplingUMesh *Build0DMeshFromCoords(DataArrayDouble *da) throw(INTERP_KERNEL::Exception); static MEDCouplingUMesh *MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2) throw(INTERP_KERNEL::Exception); static MEDCouplingUMesh *MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2) throw(INTERP_KERNEL::Exception);