Logo Search packages:      
Sourcecode: opencascade version File versions  Download package

Standard_Boolean ShapeFix_Wire::FixGap3d ( const Standard_Integer  num,
const Standard_Boolean  convert = Standard_False 
)

Fixes gap between ends of 3d curves on num-1 and num-th edges.
myPrecision is used to detect the gap.
If convert is True, converts curves to bsplines to bend.

Definition at line 162 of file ShapeFix_Wire_1.cxx.

References TopoDS_Builder::Add(), Standard_Failure::Caught(), Precision::Confusion(), ShapeFix_Root::Context(), Geom_Geometry::Copy(), ShapeAnalysis_TransferParametersProj::CopyNMVertex(), ShapeBuild_Edge::CopyReplaceVertices(), ShapeAnalysis_Edge::Curve3d(), gp_Pnt::Distance(), TopoDS_Shape::EmptyCopied(), ShapeExtend::EncodeStatus(), Geom_Curve::FirstParameter(), ShapeAnalysis_Edge::FirstVertex(), GeomAPI_ProjectPointOnCurve::Init(), Standard_Transient::IsKind(), ShapeAnalysis_Curve::IsPeriodic(), TopoDS_Shape::IsSame(), Geom_Curve::LastParameter(), ShapeAnalysis_Edge::LastVertex(), GeomAPI_ExtremaCurveCurve::LowerDistanceParameters(), gp_XYZ::Modulus(), TopoDS_Iterator::More(), GeomAPI_ExtremaCurveCurve::NbExtrema(), GeomAPI_ProjectPointOnCurve::NbPoints(), TopoDS_Iterator::Next(), TopoDS_Shape::Orientation(), TopoDS_Shape::Oriented(), GeomAPI_ProjectPointOnCurve::Parameter(), GeomAPI_ExtremaCurveCurve::Parameters(), Precision::PConfusion(), BRep_Tool::Pnt(), GeomAPI_ProjectPointOnCurve::Point(), ShapeFix_Root::Precision(), BRep_Builder::SameRange(), ShapeFix_Root::SetContext(), ShapeBuild_Edge::SetRange3d(), ShapeFix_ShapeTolerance::SetTolerance(), GeomConvert::SplitBSplineCurve(), BRep_Builder::UpdateEdge(), TopoDS_Iterator::Value(), and WireData().

Referenced by FixGaps3d().

{
  myLastFixStatus = ShapeExtend::EncodeStatus( ShapeExtend_OK );
//  if ( !IsReady() ) return Standard_False;

  //=============
  // First phase: analysis whether the problem (gap) exists
  //=============

  if (Context().IsNull()) SetContext(new ShapeBuild_ReShape);

  Standard_Real preci = Precision();

  Handle(ShapeExtend_WireData) sbwd = WireData();
  Standard_Integer n2 = ( num >0 ? num  : sbwd->NbEdges() );
  Standard_Integer n1 = ( n2  >1 ? n2-1 : sbwd->NbEdges() );
//smh#8
  TopoDS_Shape tmp1 = Context()->Apply(sbwd->Edge(n1)),
               tmp2 = Context()->Apply(sbwd->Edge(n2));
  TopoDS_Edge E1 = TopoDS::Edge(tmp1),
              E2 = TopoDS::Edge(tmp2);
//  TopoDS_Face face = myAnalyzer->Face(); // comment by enk 

  // Retrieve curves on edges
  Standard_Real cfirst1, clast1, cfirst2, clast2;
  Handle(Geom_Curve) C1, C2;
  ShapeAnalysis_Edge SAE;
  if (!SAE.Curve3d(E1,C1,cfirst1,clast1) ||
      !SAE.Curve3d(E2,C2,cfirst2,clast2)) 
  {
    myLastFixStatus |= ShapeExtend::EncodeStatus( ShapeExtend_FAIL1 );
    return Standard_False;
  }
  
  // Check gap in 3d space
  gp_Pnt cpnt1 = C1->Value(clast1), cpnt2 = C2->Value(cfirst2);
  Standard_Real gap = cpnt1.Distance(cpnt2);
  if (!convert && gap<=preci) return Standard_False;
    
  //=============
  // Second phase: collecting data necessary for further analysis
  //=============

  Standard_Boolean reversed1 = (E1.Orientation()==TopAbs_REVERSED),
                   reversed2 = (E2.Orientation()==TopAbs_REVERSED);

  TopoDS_Vertex V1 = SAE.LastVertex(E1), V2 = SAE.FirstVertex(E2);
  gp_Pnt vpnt = (V1.IsSame(V2))? BRep_Tool::Pnt(V1) :
    gp_Pnt((BRep_Tool::Pnt(V1).XYZ()+BRep_Tool::Pnt(V2).XYZ())*0.5);

  Standard_Real first1, last1, first2, last2;
  if (reversed1) 
  { 
    first1 = clast1;  last1 = cfirst1; 
  }
  else           
  { 
    first1 = cfirst1; last1 = clast1;  
  }
  if (reversed2) 
  { 
    first2 = clast2;  last2 = cfirst2; 
  }
  else           
  { 
    first2 = cfirst2; last2 = clast2;  
  }

  Handle(Geom_Curve) c1 = C1, c2 = C2;

  // Extract basic curves from trimmed and offset
  Standard_Boolean basic = Standard_False;
  Standard_Boolean trimmed1 = Standard_False, offset1 = Standard_False;
  gp_XYZ offval1(0.,0.,0.);
  while (!basic) 
  {
    if (c1->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))) 
    {
      c1 = Handle(Geom_TrimmedCurve)::DownCast(c1)->BasisCurve();
      trimmed1 = Standard_True;
    }
    else if (c1->IsKind(STANDARD_TYPE(Geom_OffsetCurve))) 
    {
      Handle(Geom_OffsetCurve) oc = Handle(Geom_OffsetCurve)::DownCast(c1);
      c1 = oc->BasisCurve();
      offval1 += oc->Offset()*oc->Direction().XYZ();
      offset1 = Standard_True;
    }
    else basic = Standard_True;
  }
  basic = Standard_False;
  Standard_Boolean trimmed2 = Standard_False, offset2 = Standard_False;
  gp_XYZ offval2(0.,0.,0.);
  while (!basic) 
  {
    if (c2->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))) 
    {
      c2 = Handle(Geom_TrimmedCurve)::DownCast(c2)->BasisCurve();
      trimmed2 = Standard_True;
    }
    else if (c2->IsKind(STANDARD_TYPE(Geom_OffsetCurve))) 
    {
      Handle(Geom_OffsetCurve) oc = Handle(Geom_OffsetCurve)::DownCast(c2);
      c2 = oc->BasisCurve();
      offval2 += oc->Offset()*oc->Direction().XYZ();
      offset2 = Standard_True;
    }
    else basic = Standard_True;
  }
  // Restore offset curves
  if (offset1) c1 = new Geom_OffsetCurve(c1,offval1.Modulus(),gp_Dir(offval1));
  if (offset2) c2 = new Geom_OffsetCurve(c2,offval2.Modulus(),gp_Dir(offval2));

  Standard_Boolean done1 = Standard_False, done2 = Standard_False;

  if (convert) 
  {

    Handle(Geom_BSplineCurve) bsp1, bsp2;
    Handle(Geom_Curve) c;
    Standard_Real first, last;

    // iterate on curves
    Standard_Integer nbcurv = (n1==n2? 1 : 2);
    for (Standard_Integer j=1; j<=nbcurv; j++) 
    {
      //Standard_Boolean trim = Standard_False;  // skl
      if (j==1) 
      {
      if (cpnt1.Distance(vpnt)<preci) 
        {
        if (n1==n2) 
          { 
            if (cpnt2.Distance(vpnt)<preci) continue; 
          }
        else continue;
      }
      c = c1; first = first1; last = last1; /*trim = trimmed1;*/ // skl
      }
      else 
      {
      if (cpnt2.Distance(vpnt)<preci) continue;
      c = c2; first = first2; last = last2; /*trim = trimmed2;*/ // skl
      }

      Handle(Geom_BSplineCurve) bsp;

      // Convert curve to bspline
      if (c->IsKind(STANDARD_TYPE(Geom_BSplineCurve))) 
      {
      bsp = Handle(Geom_BSplineCurve)::DownCast(c->Copy());
      // take segment if trim and range differ
      Standard_Real fbsp = bsp->FirstParameter(), lbsp = bsp->LastParameter();
      Standard_Boolean segment = Standard_False;
      if (first>fbsp) 
        { 
          fbsp = first; segment = Standard_True; 
        }
      if (last<lbsp) 
        { 
          lbsp = last; segment = Standard_True; 
        }
      if (segment)
        bsp = GeomConvert::SplitBSplineCurve(bsp,fbsp,lbsp,
                                     ::Precision::Confusion());
      }
      else if (c->IsKind(STANDARD_TYPE(Geom_Conic))) 
      {
      Approx_Curve3d Conv(new GeomAdaptor_HCurve(c,first,last),
                      myAnalyzer->Precision(),GeomAbs_C1,9,1000);
      if (Conv.IsDone() || Conv.HasResult()) bsp = Conv.Curve();
      }
      else 
      {
      // Restore trim for pcurve
      Handle(Geom_Curve) tc ;     
      try 
        {
          OCC_CATCH_SIGNALS
          // 15.11.2002 PTV OCC966
        if(!ShapeAnalysis_Curve::IsPeriodic(c))
          tc = new Geom_TrimmedCurve(c,Max(first,c->FirstParameter()),Min(last,c->LastParameter()));
        else tc = new Geom_TrimmedCurve(c,first,last);
        bsp = GeomConvert::CurveToBSplineCurve(tc);
      }
      catch (Standard_Failure) 
        {
#ifdef DEB 
        cout << "Warning: ShapeFix_Wire_1::FixGap3d: Exception in TrimmedCurve" <<first<<" " <<last<<endl;
        Standard_Failure::Caught()->Print(cout); cout << endl; 
#endif  
      }
      }

      if (j==1) bsp1 = bsp; else bsp2 = bsp;
    }
    
    // Take curves ends if could not convert
    if (bsp1.IsNull()) vpnt = cpnt1;
    else if (bsp2.IsNull()) vpnt = cpnt2;

    if (!bsp1.IsNull()) 
    {
      if(bsp1->Degree() == 1) bsp1->IncreaseDegree(2); //gka
      if (n1==n2) 
      { 
        bsp1->SetPole(1,vpnt); bsp1->SetPole(bsp1->NbPoles(),vpnt); 
      }
      else 
      {
      if (reversed1) bsp1->SetPole(1,vpnt);
      else bsp1->SetPole(bsp1->NbPoles(),vpnt);
      }
      first1 = bsp1->FirstParameter(); last1 = bsp1->LastParameter();
      c1 = bsp1;
      done1 = Standard_True;
    }
    if (!bsp2.IsNull()) 
    {
      if(bsp2->Degree() == 1) bsp2->IncreaseDegree(2); //gka
      if (reversed2) bsp2->SetPole(bsp2->NbPoles(),vpnt);
      else bsp2->SetPole(1,vpnt);
      first2 = bsp2->FirstParameter(); last2 = bsp2->LastParameter();
      c2 = bsp2;
      done2 = Standard_True;
    }
  }
  else 
  {

    if (n1==n2) 
    {
      if (c1->IsKind(STANDARD_TYPE(Geom_Circle)) ||
        c1->IsKind(STANDARD_TYPE(Geom_Ellipse))) 
      {
      Standard_Real diff = PI - Abs(clast1-cfirst2)*0.5;
      first1 -= diff; last1 += diff;
      done1 = Standard_True;
      }
    }
    else 
    {

      // Determine domains for extremal points locating
      Standard_Real domfirst1 = first1, domlast1 = last1;
      if (c1->IsKind(STANDARD_TYPE(Geom_BSplineCurve)) ||
        c1->IsKind(STANDARD_TYPE(Geom_BezierCurve))) 
      {
      domfirst1 = c1->FirstParameter();
      domlast1  = c1->LastParameter();
      }
      else if (c1->IsKind(STANDARD_TYPE(Geom_Line)) ||
             c1->IsKind(STANDARD_TYPE(Geom_Parabola)) ||
             c1->IsKind(STANDARD_TYPE(Geom_Hyperbola))) 
      {
      Standard_Real diff = domlast1 - domfirst1;
      if (reversed1) domfirst1 -= 10.*diff;
      else           domlast1 += 10.*diff;
      }
      else if (c1->IsKind(STANDARD_TYPE(Geom_Circle)) ||
             c1->IsKind(STANDARD_TYPE(Geom_Ellipse))) 
      {
      domfirst1 = 0.; domlast1 = 2*PI;
      }
      Standard_Real domfirst2 = first2, domlast2 = last2;
      if (c2->IsKind(STANDARD_TYPE(Geom_BSplineCurve)) ||
        c2->IsKind(STANDARD_TYPE(Geom_BezierCurve))) 
      {
      domfirst2 = c2->FirstParameter();
      domlast2  = c2->LastParameter();
      }
      else if (c2->IsKind(STANDARD_TYPE(Geom_Line)) ||
             c2->IsKind(STANDARD_TYPE(Geom_Parabola)) ||
             c2->IsKind(STANDARD_TYPE(Geom_Hyperbola))) 
      {
      Standard_Real diff = domlast2 - domfirst2;
      if (reversed2) domlast2 += 10.*diff;
      else           domfirst2 -= 10.*diff;
      }
      else if (c2->IsKind(STANDARD_TYPE(Geom_Circle)) ||
             c2->IsKind(STANDARD_TYPE(Geom_Ellipse))) 
      {
      domfirst2 = 0.; domlast2 = 2*PI;
      }

      Standard_Real ipar1 = clast1, ipar2 = cfirst2;

      // Try to find projections of vertex point
      GeomAPI_ProjectPointOnCurve Proj;
      Standard_Real u1 = ipar1, u2 = ipar2;
      Proj.Init(vpnt,c1,domfirst1,domlast1);
      if (Proj.NbPoints()) 
      {
      Standard_Integer index = 1;
      Standard_Real dist, mindist=-1.;
      for (Standard_Integer i=1; i<=Proj.NbPoints(); i++) 
        {
        dist = vpnt.Distance(Proj.Point(i));
        if (mindist>dist || mindist<0.) 
          { 
            index = i; mindist = dist; 
          }
        u1 = Proj.Parameter(index);
      }
      }
      Proj.Init(vpnt,c2,domfirst2,domlast2);
      if (Proj.NbPoints()) 
      {
      Standard_Integer index = 1;
      Standard_Real dist, mindist=-1.;
      for (Standard_Integer i=1; i<=Proj.NbPoints(); i++) 
        {
        dist = vpnt.Distance(Proj.Point(i));
        if (mindist>dist || mindist<0.) 
          { 
            index = i; mindist = dist; 
          }
        u2 = Proj.Parameter(index);
      }
      }
      // Ajust parameters on periodic curves
      u1 = AdjustOnPeriodic3d(c1,reversed1,first1,last1,u1);
      u2 = AdjustOnPeriodic3d(c2,!reversed2,first2,last2,u2);
      // Check points to satisfy distance criterium
      gp_Pnt p1 = c1->Value(u1), p2 = c2->Value(u2);
      if (p1.Distance(p2)<=gap &&
        Abs(cfirst1-u1) > ::Precision::PConfusion() &&
        Abs(clast2-u2) > ::Precision::PConfusion() &&
        (((u1>first1) && (u1<last1)) || ((u2>first2) && (u2<last2)) ||
         (cpnt1.Distance(p1)<=gap) || (cpnt2.Distance(p2)<=gap))) 
      {
      ipar1 = u1; ipar2 = u2;
      done1 = done2 = Standard_True;
      }

      // Try to find closest points if nothing yet found
      if (!done1) 
      {

      // Recompute domains
      if (reversed1) 
        { 
          domfirst1 = ipar1; domlast1 = last1; 
        }
      else 
        { 
          domfirst1 = first1; domlast1 = ipar1; 
        }
      if (reversed2) 
        { 
          domfirst2 = first2; domlast2 = ipar2; 
        }
      else 
        { 
          domfirst2 = ipar2; domlast2 = last2; 
        }

      GeomAPI_ExtremaCurveCurve Extr(c1,c2,domfirst1,domlast1,domfirst2,domlast2);
      if (Extr.NbExtrema()) 
        {
        try 
          {
            OCC_CATCH_SIGNALS
          // First find all intersections
          gp_Pnt pp1, pp2;
          Standard_Integer index1=0, index2=0;
          Standard_Real uu1, uu2, pardist, pardist1=-1., pardist2=-1.;
          for (Standard_Integer i=1; i<=Extr.NbExtrema(); i++) 
            {
            Extr.Parameters(i,uu1,uu2);
            // Ajust parameters on periodic curves
            uu1 = AdjustOnPeriodic3d(c1,reversed1,first1,last1,uu1);
            uu2 = AdjustOnPeriodic3d(c2,!reversed2,first2,last2,uu2);
            pp1 = c1->Value(uu1); pp2 = c2->Value(uu2);
            if (pp1.Distance(pp2) < ::Precision::Confusion()) 
              {
            // assume intersection
            pardist = Abs(cfirst1-uu1);
            if (pardist1>pardist || pardist1<0.) 
                { 
                  index1 = i; pardist1 = pardist; 
                }
            pardist = Abs(clast2-uu2);
            if (pardist2>pardist || pardist2<0.) 
                { 
                  index2 = i; pardist2 = pardist; 
                }
            }
          }
          if (index1!=0 && index2!=0) 
            {
            if (index1!=index2) 
              {
            // take intersection closer to vertex point
            Extr.Parameters(index1,uu1,uu2);
            pp1 = gp_Pnt((c1->Value(uu1).XYZ()+c2->Value(uu2).XYZ())*0.5);
            Extr.Parameters(index2,uu1,uu2);
            pp2 = gp_Pnt((c1->Value(uu1).XYZ()+c2->Value(uu2).XYZ())*0.5);
            if (pp2.Distance(vpnt) < pp1.Distance(vpnt)) index1 = index2;
            }
            Extr.Parameters(index1,uu1,uu2);
          }
          else Extr.LowerDistanceParameters(uu1,uu2);
          // Ajust parameters on periodic curves
          uu1 = AdjustOnPeriodic3d(c1,reversed1,first1,last1,uu1);
          uu2 = AdjustOnPeriodic3d(c2,!reversed2,first2,last2,uu2);
          // Check points to satisfy distance criterium
          pp1 = c1->Value(uu1), pp2 = c2->Value(uu2);
          if (pp1.Distance(pp2)<=gap &&
            Abs(cfirst1-uu1) > ::Precision::PConfusion() &&
            Abs(clast2-uu2) > ::Precision::PConfusion() &&
            (((uu1>first1) && (uu1<last1)) || ((uu2>first2) && (uu2<last2)) ||
             (cpnt1.Distance(pp1)<=gap) || (cpnt2.Distance(pp2)<=gap))) 
            {
            ipar1 = uu1; ipar2 = uu2;
            done1 = done2 = Standard_True;
          }
        }
        catch ( Standard_Failure ) 
          {
          }
      }
      }
      
      try 
      {
        OCC_CATCH_SIGNALS
      if (done1) 
        {
        if (ipar1==clast1) done1 = Standard_False;
        else 
          {
          // Set up new bounds for curve
          if (reversed1) first1 = ipar1; else last1 = ipar1;
          // Set new trim for old curve
          if (trimmed1) 
            {
            // Standard_Real ff1 = c1->FirstParameter();
            // Standard_Real ll1 = c1->LastParameter();
            c1 = new Geom_TrimmedCurve(c1,first1,last1);
          }
        }
      }
      if (done2) 
        {
        if (ipar2==cfirst2) done2 = Standard_False;
        else 
          {
          // Set up new bounds for curve
          if (reversed2) last2 = ipar2; else first2 = ipar2;
          // Set new trim for old curve
          if (trimmed2) 
            {
            // Standard_Real ff2 = c2->FirstParameter();
            // Standard_Real ll2 = c2->LastParameter();
            c2 = new Geom_TrimmedCurve(c2,first2,last2);
          }
        }
      }
      }
      catch (Standard_Failure) 
      {
#ifdef DEB       
      cout << "Warning: ShapeFix_Wire_1::FixGap3d: Exception in TrimmedCurve      :"<<endl;
      Standard_Failure::Caught()->Print(cout); cout << endl;
#endif
      }  
    }
  }
  
  if (done1 || done2) 
  {

    BRep_Builder B;
    ShapeBuild_Edge SBE;
    ShapeFix_ShapeTolerance SFST;

    // Update vertices
    TopoDS_Vertex nullV, newV1;
//smh#8
    TopoDS_Shape emptyCopiedV2 = V2.EmptyCopied();
    TopoDS_Vertex newV2 = TopoDS::Vertex(emptyCopiedV2);
    SFST.SetTolerance(newV2,::Precision::Confusion());
    Context()->Replace(V2,newV2);
    if (V1.IsSame(V2))
//smh#8
      {
      TopoDS_Shape tmpV2 = newV2.Oriented(TopAbs_REVERSED);
      newV1 = TopoDS::Vertex(tmpV2);
      }
    else 
    {
//smh#8
      TopoDS_Shape emptyCopied = V1.EmptyCopied();
      newV1 = TopoDS::Vertex(emptyCopied);
      SFST.SetTolerance(newV1,::Precision::Confusion());
      Context()->Replace(V1,newV1);
    }

    if (done1) 
    {
      // Update first edge
      TopoDS_Edge newE1 = SBE.CopyReplaceVertices(E1,nullV,newV1);
//smh#8
      TopoDS_Shape tmpE1 = newE1.Oriented(TopAbs_FORWARD);
      B.UpdateEdge(TopoDS::Edge(tmpE1),c1,0.);
      SBE.SetRange3d(TopoDS::Edge(tmpE1),first1,last1);
      SFST.SetTolerance(newE1,::Precision::Confusion(),TopAbs_EDGE);
      B.SameRange(newE1,Standard_False);
//      B.SameParameter(newE1,Standard_False);
      
      //To keep NM vertices belonging initial edges
      TopoDS_Iterator aItv(E1,Standard_False);
      for( ; aItv.More(); aItv.Next()) {
      if(aItv.Value().Orientation() == TopAbs_INTERNAL ||
         aItv.Value().Orientation() == TopAbs_EXTERNAL) {
        TopoDS_Vertex aOldV = TopoDS::Vertex(aItv.Value());
        TopoDS_Vertex anewV =  ShapeAnalysis_TransferParametersProj::CopyNMVertex(aOldV,newE1,E1);
        B.Add(newE1,anewV);
        Context()->Replace(aOldV,anewV);
      }
      }
      
      Context()->Replace(E1,newE1);
      sbwd->Set(newE1,n1);
    }

    if (done2) 
    {
      // Update second edge
      TopoDS_Edge newE2 = SBE.CopyReplaceVertices(E2,newV2,nullV);
//smh#8
      TopoDS_Shape tmpE2 = newE2.Oriented(TopAbs_FORWARD);
      B.UpdateEdge(TopoDS::Edge(tmpE2),c2,0.);
      SBE.SetRange3d(TopoDS::Edge(tmpE2),first2,last2);
      SFST.SetTolerance(newE2,::Precision::Confusion(),TopAbs_EDGE);
      B.SameRange(newE2,Standard_False);
//      B.SameParameter(newE2,Standard_False);
      
      //To keep NM vertices belonging initial edges
      TopoDS_Iterator aItv(E2,Standard_False);
      for( ; aItv.More(); aItv.Next()) {
      if(aItv.Value().Orientation() == TopAbs_INTERNAL ||
         aItv.Value().Orientation() == TopAbs_EXTERNAL) {
        TopoDS_Vertex aOldV = TopoDS::Vertex(aItv.Value());
        TopoDS_Vertex anewV =  ShapeAnalysis_TransferParametersProj::CopyNMVertex(aOldV,newE2,E2);
        B.Add(newE2,anewV);
        Context()->Replace(aOldV,anewV);
      }
      }
      Context()->Replace(E2,newE2);
      sbwd->Set(newE2,n2);
    }

    myLastFixStatus |= ShapeExtend::EncodeStatus( ShapeExtend_DONE1 );
  }
  else
    if (convert)
      myLastFixStatus |= ShapeExtend::EncodeStatus( ShapeExtend_FAIL2 );

  return (done1 || done2);
}


Generated by  Doxygen 1.6.0   Back to index