+//=======================================================================
+//function : fixOverlappedLinkUV
+//purpose : prevent failure due to overlapped adjacent links
+//=======================================================================
+
+static bool fixOverlappedLinkUV( R2& uv0, const R2& uv1, const R2& uv2 )
+{
+ gp_XY v1( uv0.x - uv1.x, uv0.y - uv1.y );
+ gp_XY v2( uv2.x - uv1.x, uv2.y - uv1.y );
+
+ double tol2 = DBL_MIN * DBL_MIN;
+ double sqMod1 = v1.SquareModulus();
+ if ( sqMod1 <= tol2 ) return false;
+ double sqMod2 = v2.SquareModulus();
+ if ( sqMod2 <= tol2 ) return false;
+
+ double dot = v1*v2;
+
+ // check sinus >= 1.e-3
+ const double minSin = 1.e-3;
+ if ( dot > 0 && 1 - dot * dot / ( sqMod1 * sqMod2 ) < minSin * minSin ) {
+ MESSAGE(" ___ FIX UV ____" << uv0.x << " " << uv0.y);
+ v1.SetCoord( -v1.Y(), v1.X() );
+ double delta = sqrt( sqMod1 ) * minSin;
+ if ( v1.X() < 0 )
+ uv0.x -= delta;
+ else
+ uv0.x += delta;
+ if ( v1.Y() < 0 )
+ uv0.y -= delta;
+ else
+ uv0.y += delta;
+// MESSAGE(" -> " << uv0.x << " " << uv0.y << " ");
+// MESSAGE("v1( " << v1.X() << " " << v1.Y() << " ) " <<
+// "v2( " << v2.X() << " " << v2.Y() << " ) ");
+// MESSAGE("SIN: " << sqrt(1 - dot * dot / (sqMod1 * sqMod2)));
+// v1.SetCoord( uv0.x - uv1.x, uv0.y - uv1.y );
+// v2.SetCoord( uv2.x - uv1.x, uv2.y - uv1.y );
+// gp_XY v3( uv2.x - uv0.x, uv2.y - uv0.y );
+// sqMod1 = v1.SquareModulus();
+// sqMod2 = v2.SquareModulus();
+// dot = v1*v2;
+// double sin = sqrt(1 - dot * dot / (sqMod1 * sqMod2));
+// MESSAGE("NEW SIN: " << sin);
+ return true;
+ }
+ return false;
+}
+
+//=======================================================================
+//function : fixCommonVertexUV
+//purpose :
+//=======================================================================
+
+static bool fixCommonVertexUV (gp_Pnt2d & theUV,
+ const TopoDS_Vertex& theV,
+ const TopoDS_Wire& theW,
+ const TopoDS_Wire& theOW,
+ const TopoDS_Face& theF,
+ const TopTools_IndexedDataMapOfShapeListOfShape & theVWMap,
+ SMESH_Mesh & theMesh)
+{
+ if( theW.IsSame( theOW ) ||
+ !theVWMap.Contains( theV )) return false;
+
+ // check if there is another wire sharing theV
+ const TopTools_ListOfShape& WList = theVWMap.FindFromKey( theV );
+ TopTools_ListIteratorOfListOfShape aWIt;
+ for ( aWIt.Initialize( WList ); aWIt.More(); aWIt.Next() )
+ if ( !theW.IsSame( aWIt.Value() ))
+ break;
+ if ( !aWIt.More() ) return false;
+
+ TopTools_ListOfShape EList;
+ list< double > UList;
+
+ // find edges of theW sharing theV
+ // and find 2d normal to them at theV
+ gp_Vec2d N(0.,0.);
+ TopoDS_Iterator itE( theW );
+ for ( ; itE.More(); itE.Next() )
+ {
+ const TopoDS_Edge& E = TopoDS::Edge( itE.Value() );
+ TopoDS_Iterator itV( E );
+ for ( ; itV.More(); itV.Next() )
+ {
+ const TopoDS_Vertex & V = TopoDS::Vertex( itV.Value() );
+ if ( !V.IsSame( theV ))
+ continue;
+ EList.Append( E );
+ Standard_Real u = BRep_Tool::Parameter( V, E );
+ UList.push_back( u );
+ double f, l;
+ Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface(E, theF, f, l);
+ gp_Vec2d d1;
+ gp_Pnt2d p;
+ C2d->D1( u, p, d1 );
+ gp_Vec2d n( d1.Y(), -d1.X() );
+ if ( E.Orientation() == TopAbs_REVERSED )
+ n.Reverse();
+ N += n.Normalized();
+ }
+ }
+
+ // define step size by which to move theUV
+
+ gp_Pnt2d nextUV; // uv of next node on edge, most distant of the four
+ double maxDist = -DBL_MAX;
+ TopTools_ListIteratorOfListOfShape aEIt (EList);
+ list< double >::iterator aUIt = UList.begin();
+ for ( ; aEIt.More(); aEIt.Next(), aUIt++ )
+ {
+ const TopoDS_Edge& E = TopoDS::Edge( aEIt.Value() );
+ double f, l;
+ Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface(E, theF, f, l);
+
+ double umin = DBL_MAX, umax = -DBL_MAX;
+ SMDS_NodeIteratorPtr nIt = theMesh.GetSubMesh(E)->GetSubMeshDS()->GetNodes();
+ if ( !nIt->more() ) // no nodes on edge, only on vertices
+ {
+ umin = l;
+ umax = f;
+ }
+ else
+ {
+ while ( nIt->more() ) {
+ const SMDS_MeshNode* node = nIt->next();
+ const SMDS_EdgePosition* epos =
+ static_cast<const SMDS_EdgePosition*>(node->GetPosition().get());
+ double u = epos->GetUParameter();
+ if ( u < umin )
+ umin = u;
+ if ( u > umax )
+ umax = u;
+ }
+ }
+ bool isFirstCommon = ( *aUIt == f );
+ gp_Pnt2d uv = C2d->Value( isFirstCommon ? umin : umax );
+ double dist = theUV.SquareDistance( uv );
+ if ( dist > maxDist ) {
+ maxDist = dist;
+ nextUV = uv;
+ }
+ }
+ R2 uv0, uv1, uv2;
+ uv0.x = theUV.X(); uv0.y = theUV.Y();
+ uv1.x = nextUV.X(); uv1.y = nextUV.Y();
+ uv2.x = uv0.x; uv2.y = uv0.y;
+ if ( fixOverlappedLinkUV( uv0, uv1, uv2 ))
+ {
+ double step = theUV.Distance( gp_Pnt2d( uv0.x, uv0.y ));
+
+ // move theUV along the normal by the step
+
+ N *= step;
+
+ MESSAGE("--fixCommonVertexUV move(" << theUV.X() << " " << theUV.Y()
+ << ") by (" << N.X() << " " << N.Y() << ")"
+ << endl << "--- MAX DIST " << maxDist);
+
+ theUV.SetXY( theUV.XY() + N.XY() );
+
+ return true;
+ }
+ return false;
+}
+