* \sa MEDCouplingUMesh::conformize2D, MEDCouplingUMesh::mergeNodes, MEDCouplingUMesh::convexEnvelop2D.
*/
DataArrayInt *MEDCouplingUMesh::colinearize2D(double eps)
+{
+ internalColinearize2D(eps, false);
+}
+
+/*!
+ * Performs exactly the same job as colinearize2D, except that this function does not create new non-conformal cells.
+ * In a given 2D cell, if two edges are colinear and the junction point is used by a third edge, the two edges will not be
+ * merged, contrary to colinearize2D().
+ *
+ * \sa MEDCouplingUMesh::colinearize2D
+ */
+DataArrayInt *MEDCouplingUMesh::colinearizeKeepingConform2D(double eps)
+{
+ internalColinearize2D(eps, true);
+}
+
+
+/*!
+ * \param stayConform is set to True, will not fuse two edges sharing a node that has (strictly) more than 2 egdes connected to it
+ */
+DataArrayInt *MEDCouplingUMesh::internalColinearize2D(double eps, bool stayConform)
{
MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
checkCoherency();
int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
const int *cptr(_nodal_connec->begin()),*ciptr(_nodal_connec_index->begin());
MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newc(DataArrayInt::New()),newci(DataArrayInt::New()); newci->alloc(nbOfCells+1,1); newc->alloc(0,1); newci->setIJ(0,0,0);
+ std::map<int, bool> forbiddenPoints; // list of points that can not be removed (or it will break conformity)
+ if(stayConform) //
+ {
+ // A point that is used by more than 2 edges can not be removed without breaking conformity:
+ MEDCouplingAutoRefCountObjectPtr<DataArrayInt> desc1(DataArrayInt::New()),descI1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescI1(DataArrayInt::New());
+ MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> mDesc1D(buildDescendingConnectivity(desc1,descI1,revDesc1,revDescI1));
+ MEDCouplingAutoRefCountObjectPtr<DataArrayInt> desc2(DataArrayInt::New()),descI2(DataArrayInt::New()),revDesc2(DataArrayInt::New()),revDescI2(DataArrayInt::New());
+ MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> mDesc0D(mDesc1D->buildDescendingConnectivity(desc2,descI2,revDesc2,revDescI2));
+ MEDCouplingAutoRefCountObjectPtr<DataArrayInt> dsi(revDescI2->deltaShiftIndex());
+ MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ids(dsi->getIdsInRange(3, 10000));
+ const int * cPtr(mDesc0D->getNodalConnectivity()->begin());
+ for(const int* it = ids->begin(); it != ids->end(); it++)
+ forbiddenPoints[cPtr[2*(*it)+1]] = true; // we know that a 0D mesh has a connectivity of the form [NORM_POINT1, i1, NORM_POINT1, i2, ...]
+ }
+
MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> appendedCoords(DataArrayDouble::New()); appendedCoords->alloc(0,1);//1 not 2 it is not a bug.
const double *coords(_coords->begin());
int *newciptr(newci->getPointer());
for(int i=0;i<nbOfCells;i++,newciptr++,ciptr++)
{
- if(Colinearize2DCell(coords,cptr+ciptr[0],cptr+ciptr[1],nbOfNodes,newc,appendedCoords))
+ if(Colinearize2DCell(coords,cptr+ciptr[0],cptr+ciptr[1],nbOfNodes,forbiddenPoints, /*out*/ newc,appendedCoords))
ret->pushBackSilent(i);
newciptr[1]=newc->getNumberOfTuples();
}
* Returns true if a colinearization has been found in the given cell. If false is returned the content pushed in \a newConnOfCell is equal to [ \a connBg , \a connEnd ) .
* \a appendedCoords is a DataArrayDouble instance with number of components equal to one (even if the items are pushed by pair).
*/
-bool MEDCouplingUMesh::Colinearize2DCell(const double *coords, const int *connBg, const int *connEnd, int offset, DataArrayInt *newConnOfCell, DataArrayDouble *appendedCoords)
+bool MEDCouplingUMesh::Colinearize2DCell(const double *coords, const int *connBg, const int *connEnd, int offset,
+ const std::map<int, bool>& forbiddenPoints,
+ DataArrayInt *newConnOfCell, DataArrayDouble *appendedCoords)
{
std::size_t sz(std::distance(connBg,connEnd));
if(sz<3)//3 because 2+1(for the cell type) and 2 is the minimal number of edges of 2D cell.
throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Colinearize2DCell : the input cell has invalid format !");
sz--;
INTERP_KERNEL::AutoPtr<int> tmpConn(new int[sz]);
+ INTERP_KERNEL::AutoPtr<int> tmpConn2(new int[sz]);
const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connBg[0]));
unsigned nbs(cm.getNumberOfSons2(connBg+1,sz));
unsigned nbOfHit(0); // number of fusions operated
// This initializes posBaseElt.
if(nbOfTurn==0)
{
- for(unsigned i=1;i<nbs && nbOfHit<maxNbOfHit;i++) // 2nd condition is to avoid ending with a cell wih one single edge
+ for(unsigned i=1;i<nbs && nbOfHit<maxNbOfHit;i++) // 2nd condition is to avoid ending with a cell with one single edge
{
- cm.fillSonCellNodalConnectivity2(nbs-i,connBg+1,sz,tmpConn,typeOfSon);
- INTERP_KERNEL::Edge *eCand(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
+ cm.fillSonCellNodalConnectivity2(nbs-i,connBg+1,sz,tmpConn2,typeOfSon);
+ // Identify common point:
+ int commPoint = std::find((int *)tmpConn, tmpConn+2, tmpConn2[0]) != tmpConn+2 ? tmpConn2[0] : tmpConn2[1];
+ std::map<int, bool>::const_iterator itE(forbiddenPoints.end());
+ if (forbiddenPoints.find(commPoint) != itE) // is the junction point in the list of points we can not remove?
+ break;
+ INTERP_KERNEL::Edge *eCand(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn2,coords,m));
INTERP_KERNEL::EdgeIntersector *eint(INTERP_KERNEL::Edge::BuildIntersectorWith(e,eCand));
bool isColinear=eint->areColinears();
if(isColinear)
eCand->decrRef();
if(!isColinear)
break;
+ // Update last connectivity
+ std::copy((int *)tmpConn2, tmpConn2+sz, (int *)tmpConn);
}
}
// Now move forward:
const unsigned fwdStart = (nbOfTurn == 0 ? 0 : posBaseElt); // the first element to be inspected going forward
- for(unsigned j=fwdStart+1;j<nbs && nbOfHit<maxNbOfHit;j++) // 2nd condition is to avoid ending with a cell wih one single edge
+ for(unsigned j=fwdStart+1;j<nbs && nbOfHit<maxNbOfHit;j++) // 2nd condition is to avoid ending with a cell with one single edge
{
- cm.fillSonCellNodalConnectivity2((int)j,connBg+1,sz,tmpConn,typeOfSon); // get edge #j's connectivity
- INTERP_KERNEL::Edge *eCand(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
+ cm.fillSonCellNodalConnectivity2((int)j,connBg+1,sz,tmpConn2,typeOfSon); // get edge #j's connectivity
+ // Identify common point:
+ int commPoint = std::find((int *)tmpConn, tmpConn+2, tmpConn2[0]) != tmpConn+2 ? tmpConn2[0] : tmpConn2[1];
+ std::map<int, bool>::const_iterator itE(forbiddenPoints.end());
+ if (forbiddenPoints.find(commPoint) != itE) // is the junction point in the list of points we can not remove?
+ break;
+ INTERP_KERNEL::Edge *eCand(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn2,coords,m));
INTERP_KERNEL::EdgeIntersector *eint(INTERP_KERNEL::Edge::BuildIntersectorWith(e,eCand));
bool isColinear(eint->areColinears());
if(isColinear)
eCand->decrRef();
if(!isColinear)
break;
+ // Update last connectivity
+ std::copy((int *)tmpConn2, tmpConn2+sz, (int *)tmpConn);
}
//push [posBaseElt,posEndElt) in newConnOfCell using e
- // The if clauses below are (volontary) not mutually exclusive: on a quad cell with 2 edges, the end of the connectivity is also its begining!
+ // The if clauses below are (voluntary) not mutually exclusive: on a quad cell with 2 edges, the end of the connectivity is also its beginning!
if(nbOfTurn==0)
- // at the begining of the connectivity (insert type)
+ // at the beginning of the connectivity (insert type)
EnterTheResultOf2DCellFirst(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
else if((nbOfHit+nbOfTurn) != (nbs-1))
// in the middle
MEDCOUPLING_EXPORT DataArrayDouble *computePlaneEquationOf3DFaces() const;
MEDCOUPLING_EXPORT DataArrayInt *conformize2D(double eps);
MEDCOUPLING_EXPORT DataArrayInt *colinearize2D(double eps);
+ MEDCOUPLING_EXPORT DataArrayInt *colinearizeKeepingConform2D(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);
const int *desc, const int *descIndx, DataArrayInt *nodalRes, DataArrayInt *nodalResIndx, DataArrayInt *cellIds) const;
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);
- static bool Colinearize2DCell(const double *coords, const int *connBg, const int *connEnd, int offset, DataArrayInt *newConnOfCell, DataArrayDouble *appendedCoords);
+ static bool Colinearize2DCell(const double *coords, const int *connBg, const int *connEnd, int offset, const std::map<int, bool>& forbiddenPoints, DataArrayInt *newConnOfCell, DataArrayDouble *appendedCoords);
static void ComputeAllTypesInternal(std::set<INTERP_KERNEL::NormalizedCellType>& types, const DataArrayInt *nodalConnec, const DataArrayInt *nodalConnecIndex);
+ DataArrayInt *internalColinearize2D(double eps, bool stayConform);
public:
MEDCOUPLING_EXPORT static DataArrayInt *ComputeRangesFromTypeDistribution(const std::vector<int>& code);
MEDCOUPLING_EXPORT static const int N_MEDMEM_ORDER=24;
self.assertTrue(m.getNodalConnectivityIndex().isEqual(DataArrayInt([0,7])))
pass
+ def testSwig2ColinearizeKeepingConform2D1(self):
+ eps = 1.0e-6
+ # Just to get a nice coords array ...
+ mm = MEDCouplingCMesh(); arr = DataArrayDouble([0.0, 1.0,2.0])
+ mm.setCoords(arr, arr); mm = mm.buildUnstructured(); coo = mm.getCoords()
+
+ mesh = MEDCouplingUMesh("M", 2)
+ mesh.setCoords(coo)
+ c = [NORM_POLYGON, 0,1,4,7,6,3, NORM_QUAD4, 1,2,5,4, NORM_QUAD4,4,5,8,7]
+ cI = [0, 7,12,17]
+ mm.setConnectivity(DataArrayInt(c),DataArrayInt(cI))
+ mm.checkConsistencyLight()
+
+ mm.colinearizeKeepingConform2D(eps)
+ c = mm.getNodalConnectivity().getValues()
+ cI = mm.getNodalConnectivityIndex().getValues()
+ self.assertEqual(c, [NORM_POLYGON, 0, 1, 4, 7, 6, NORM_POLYGON, 1, 2, 5, 4, NORM_POLYGON, 4, 5, 8, 7])
+ self.assertEqual(cI, [0,6,11,16])
+ pass
+
def testSwig2BoundingBoxForBBTree1(self):
""" This test appears simple but it checks that bounding box are correctly computed for quadratic polygons. It can help a lot to reduce the amount of intersections !
"""