Back to index

salome-geom  6.5.0
Public Member Functions | Private Member Functions | Private Attributes
GEOMImpl_Fillet1d Class Reference

GEOMImpl_Fillet1d is 1D fillet algorithm on two planar edges with given radius. More...

#include <GEOMImpl_Fillet1d.hxx>

List of all members.

Public Member Functions

Standard_EXPORT GEOMImpl_Fillet1d (const TopoDS_Edge &theEdge1, const TopoDS_Edge &theEdge2, const gp_Pln &thePlane)
 Constructor The fillet 1D algorithm initialise by two edges and plane.
Standard_EXPORT Standard_Boolean Perform (const Standard_Real theRadius)
 Makes fillet with given radius.
Standard_EXPORT TopoDS_Edge Result (const gp_Pnt &thePoint, TopoDS_Edge &theEdge1, TopoDS_Edge &theEdge2)
 Returns result fillet edge and modified edges as out parameters.

Private Member Functions

void fillPoint (GEOMImpl_Fillet1dPoint *)
 private methods
void fillDiff (GEOMImpl_Fillet1dPoint *, Standard_Real, Standard_Boolean)
void performNewton (GEOMImpl_Fillet1dPoint *, GEOMImpl_Fillet1dPoint *)
Standard_Boolean processPoint (GEOMImpl_Fillet1dPoint *, GEOMImpl_Fillet1dPoint *, Standard_Real)
 Handle (Geom_Plane) myPlane
 Handle (Geom2d_Curve) myCurve1

Private Attributes

TopoDS_Edge myEdge1
 private fields
TopoDS_Edge myEdge2
 myCurve2
Standard_Real myStart1
Standard_Real myEnd1
Standard_Real myStart2
Standard_Real myEnd2
Standard_Real myRadius
TColStd_ListOfReal myResultParams
TColStd_SequenceOfInteger myResultOrientation
Standard_Boolean myStartSide
Standard_Boolean myEdgesExchnged
Standard_Integer myDegreeOfRecursion

Detailed Description

GEOMImpl_Fillet1d is 1D fillet algorithm on two planar edges with given radius.

Definition at line 41 of file GEOMImpl_Fillet1d.hxx.


Constructor & Destructor Documentation

GEOMImpl_Fillet1d::GEOMImpl_Fillet1d ( const TopoDS_Edge &  theEdge1,
const TopoDS_Edge &  theEdge2,
const gp_Pln &  thePlane 
)

Constructor The fillet 1D algorithm initialise by two edges and plane.

class GEOMImpl_Fillet1d

Definition at line 48 of file GEOMImpl_Fillet1d.cxx.

: myEdgesExchnged( Standard_False )
{
  myPlane = new Geom_Plane(thePlane);

  BRepAdaptor_Curve aBAC1(theEdge1);
  BRepAdaptor_Curve aBAC2(theEdge2);
  if (aBAC1.GetType() < aBAC2.GetType())
  { // first curve must be more complicated
    myEdge1 = theEdge2;
    myEdge2 = theEdge1;
    myEdgesExchnged = Standard_True;
  }
  else
  {
    myEdge1 = theEdge1;
    myEdge2 = theEdge2;
  }

  Handle(Geom_Curve) aCurve1 = BRep_Tool::Curve(myEdge1, myStart1, myEnd1);
  Handle(Geom_Curve) aCurve2 = BRep_Tool::Curve(myEdge2, myStart2, myEnd2);

  myCurve1 = GeomProjLib::Curve2d(aCurve1, myStart1, myEnd1, myPlane);
  myCurve2 = GeomProjLib::Curve2d(aCurve2, myStart2, myEnd2, myPlane);

  while (myCurve1->IsPeriodic() && myStart1 >= myEnd1)
    myEnd1 += myCurve1->Period();
  while (myCurve2->IsPeriodic() && myStart2 >= myEnd2)
    myEnd2 += myCurve2->Period();

  if (aBAC1.GetType() == aBAC2.GetType())
  {
    if (myEnd2 - myStart2 < myEnd1 - myStart1)
    { // first curve must be parametrically shorter
      TopoDS_Edge anEdge = myEdge1;
      myEdge1 = myEdge2;
      myEdge2 = anEdge;
      Handle(Geom2d_Curve) aCurve = myCurve1;
      myCurve1 = myCurve2;
      myCurve2 = aCurve;
      Standard_Real a = myStart1;
      myStart1 = myStart2;
      myStart2 = a;
      a = myEnd1;
      myEnd1 = myEnd2;
      myEnd2 = a;
      myEdgesExchnged = Standard_True;
    }
  }
}

Here is the call graph for this function:


Member Function Documentation

void GEOMImpl_Fillet1d::fillDiff ( GEOMImpl_Fillet1dPoint thePoint,
Standard_Real  theDiffStep,
Standard_Boolean  theFront 
) [private]

Definition at line 205 of file GEOMImpl_Fillet1d.cxx.

{
  GEOMImpl_Fillet1dPoint* aDiff =
    new GEOMImpl_Fillet1dPoint(thePoint->GetParam() + (theFront?(theDiffStep):(-theDiffStep)));
  fillPoint(aDiff);
  if (!thePoint->ComputeDifference(aDiff))
  {
    aDiff->SetParam(thePoint->GetParam() + (theFront?(-theDiffStep):(theDiffStep)));
    fillPoint(aDiff);
    thePoint->ComputeDifference(aDiff);
  }
  delete aDiff;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void GEOMImpl_Fillet1d::fillPoint ( GEOMImpl_Fillet1dPoint thePoint) [private]

private methods

Definition at line 155 of file GEOMImpl_Fillet1d.cxx.

{
  gp_Pnt2d aPoint;
  gp_Vec2d aVec;
  const Standard_Real aTol = Precision::Confusion();
  myCurve1->D1(thePoint->GetParam(), aPoint, aVec);
  if (aVec.SquareMagnitude() < aTol)
    return;

  gp_Vec2d aPerp(((myStartSide)?-1:1) * aVec.Y(), ((myStartSide)?1:-1) * aVec.X());
  aPerp.Normalize();
  aPerp.Multiply(myRadius);
  gp_Pnt2d aCenter = aPoint.Translated(aPerp);
  thePoint->SetCenter(aCenter);

  // on the intersection point
  Standard_Boolean aValid = Standard_True;
  Geom2dAPI_ProjectPointOnCurve aProjInt(aPoint, myCurve2);
  if (aProjInt.NbPoints() && aPoint.Distance(aProjInt.NearestPoint()) < aTol)
    aValid = Standard_False;
  else
    aValid = !isRadiusIntersected(myCurve2, aPoint, aCenter, Standard_True);

  Geom2dAPI_ProjectPointOnCurve aProj(aCenter, myCurve2);
  Standard_Integer a, aNB = aProj.NbPoints();
  for(a = aNB; a > 0; a--)
  {
    if (aPoint.Distance(aProj.Point(a)) < aTol)
      continue;

    Standard_Boolean aValid2 = aValid;
    if (aValid2)
      aValid2 = !isRadiusIntersected(myCurve1, aCenter, aProj.Point(a), Standard_False);

    // checking the right parameter
    Standard_Real aParam = aProj.Parameter(a);
    while(myCurve2->IsPeriodic() && aParam < myStart2)
      aParam += myCurve2->Period();

    thePoint->AddValue(aProj.Distance(a) * aProj.Distance(a) - myRadius * myRadius,
                       (aParam >= myStart2 && aParam <= myEnd2 && aValid2));
    if (fabs(fabs(aProj.Distance(a)) - myRadius) < aTol)
      thePoint->SetParam2(aParam);
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

GEOMImpl_Fillet1d::Handle ( Geom_Plane  ) [private]

Here is the caller graph for this function:

GEOMImpl_Fillet1d::Handle ( Geom2d_Curve  ) [private]
Standard_Boolean GEOMImpl_Fillet1d::Perform ( const Standard_Real  theRadius)

Makes fillet with given radius.

Returns:
Standard_True, if at least one result computed

Definition at line 223 of file GEOMImpl_Fillet1d.cxx.

{
  myDegreeOfRecursion = 0;
  myResultParams.Clear();
  myResultOrientation.Clear();

  Standard_Real aNBSteps = 100;
  Geom2dAdaptor_Curve aGAC(myCurve1);
  switch (aGAC.GetType())
  {
    case GeomAbs_Line:
      aNBSteps = 2;
      break;
    case GeomAbs_Circle:
      aNBSteps = 4;
      break;
    case GeomAbs_Ellipse:
      aNBSteps = 5;
      break;
    case GeomAbs_BezierCurve:
    case GeomAbs_BSplineCurve:
      aNBSteps = 2 + aGAC.Degree() * aGAC.NbPoles();
      break;
    default: // unknown: maximum
      aNBSteps = 100;
  }

  myRadius = theRadius;
  Standard_Real aParam, aStep, aDStep;
  aStep = (myEnd1 - myStart1) / aNBSteps;
  aDStep = aStep/1000.;

  Standard_Integer aCycle;
  for(aCycle = 2, myStartSide = Standard_False; aCycle; myStartSide = !myStartSide, aCycle--)
  {
    GEOMImpl_Fillet1dPoint *aLeft = NULL, *aRight = NULL;

    for(aParam = myStart1 + aStep; aParam < myEnd1 || fabs(myEnd1 - aParam) < Precision::Confusion(); aParam += aStep)
    {
      if (!aLeft)
      {
        aLeft = new GEOMImpl_Fillet1dPoint(aParam - aStep);
        fillPoint(aLeft);
        fillDiff(aLeft, aDStep, Standard_True);
      }

      aRight = new GEOMImpl_Fillet1dPoint(aParam);
      fillPoint(aRight);
      fillDiff(aRight, aDStep, Standard_False);

      aLeft->FilterPoints(aRight);
      performNewton(aLeft, aRight);

      delete aLeft;
      aLeft = aRight;
    }
    delete aLeft;
  }

  if (myResultParams.Extent())
    return Standard_True;

  return Standard_False;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void GEOMImpl_Fillet1d::performNewton ( GEOMImpl_Fillet1dPoint theLeft,
GEOMImpl_Fillet1dPoint theRight 
) [private]

Definition at line 346 of file GEOMImpl_Fillet1d.cxx.

{
  Standard_Integer a;
  // check the left: if this is solution store it and remove it from the list of researching points of theLeft
  a = theLeft->HasSolution(myRadius);
  if (a)
  {
    if (theLeft->IsValid(a))
    {
      myResultParams.Append(theLeft->GetParam());
      myResultOrientation.Append(myStartSide);
    }
    return;
  }

  Standard_Real aDX = theRight->GetParam() - theLeft->GetParam();
  if ( aDX < Precision::Confusion() / 1000000.)
  {
    a = theRight->HasSolution(myRadius);
    if (a)
      if (theRight->IsValid(a))
      {
        myResultParams.Append(theRight->GetParam());
        myResultOrientation.Append(myStartSide);
      }
    return;
  }

  for(a = 1; a <= theLeft->GetNBValues(); a++)
  {
    Standard_Integer aNear = theLeft->GetNear(a);

    Standard_Real aA = (theRight->GetDiff(aNear) - theLeft->GetDiff(a)) / aDX;
    Standard_Real aB = theLeft->GetDiff(a) - aA * theLeft->GetParam();
    Standard_Real aC = theLeft->GetValue(a) - theLeft->GetDiff(a) * theLeft->GetParam() +
                       aA * theLeft->GetParam() * theLeft->GetParam() / 2.0;
    Standard_Real aDet = aB * aB - 2.0 * aA * aC;

    if ( fabs(aDet) < gp::Resolution() )
      continue;

    if (fabs(aA) < Precision::Confusion())
    { // linear case
      if (fabs(aB) > 10e-20)
      {
        Standard_Real aX0 = - aC / aB; // use extremum
        if (aX0 > theLeft->GetParam() && aX0 < theRight->GetParam())
          processPoint(theLeft, theRight, aX0);
      }
      else
      {
        processPoint(theLeft, theRight, theLeft->GetParam() + aDX / 2.0); // linear division otherwise
      }
    }
    else
    {
      if (fabs(aB) > fabs(aDet * 1000000.))
      {  // possible floating point operations accurancy errors
        processPoint(theLeft, theRight, theLeft->GetParam() + aDX / 2.0); // linear division otherwise
      }
      else
      {
        if (aDet > 0)
        { // two solutions
          aDet = sqrt(aDet);
          Standard_Boolean aRes = processPoint(theLeft, theRight, (- aB + aDet) / aA);
          if (!aRes)
            aRes = processPoint(theLeft, theRight, (- aB - aDet) / aA);
          if (!aRes)
            processPoint(theLeft, theRight, theLeft->GetParam() + aDX / 2.0); // linear division otherwise
        }
        else
        {
          Standard_Real aX0 = - aB / aA; // use extremum
          if (aX0 > theLeft->GetParam() && aX0 < theRight->GetParam())
            processPoint(theLeft, theRight, aX0);
          else
            processPoint(theLeft, theRight, theLeft->GetParam() + aDX / 2.0); // linear division otherwise
        }
      }
    }
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

Standard_Boolean GEOMImpl_Fillet1d::processPoint ( GEOMImpl_Fillet1dPoint theLeft,
GEOMImpl_Fillet1dPoint theRight,
Standard_Real  theParameter 
) [private]

Definition at line 292 of file GEOMImpl_Fillet1d.cxx.

{
  if (theParameter >= theLeft->GetParam() && theParameter < theRight->GetParam())
  {
    Standard_Real aDX = theRight->GetParam() - theLeft->GetParam();
    if (theParameter - theLeft->GetParam() < aDX / 100.)
    {
      theParameter = theLeft->GetParam() + aDX / 100.;
    }
    if (theRight->GetParam() - theParameter < aDX / 100.)
    {
      theParameter = theRight->GetParam() - aDX / 100.;
    }

    // Protection on infinite loop.
    myDegreeOfRecursion++;
    Standard_Real diffx = 0.001 * aDX;
    if (myDegreeOfRecursion > 1000)
    {
        diffx *= 10.0;
        if (myDegreeOfRecursion > 10000)
        {
            diffx *= 10.0;
            if (myDegreeOfRecursion > 100000)
            {
                return Standard_True;
            }
        }
    }

    GEOMImpl_Fillet1dPoint* aPoint1 = theLeft->Copy();
    GEOMImpl_Fillet1dPoint* aPoint2 = new GEOMImpl_Fillet1dPoint(theParameter);
    fillPoint(aPoint2);
    fillDiff(aPoint2, diffx, Standard_True);

    aPoint1->FilterPoints(aPoint2);
    performNewton(aPoint1, aPoint2);
    aPoint2->FilterPoints(theRight);
    performNewton(aPoint2, theRight);

    delete aPoint1;
    delete aPoint2;
    return Standard_True;
  }

  return Standard_False;
}

Here is the call graph for this function:

Here is the caller graph for this function:

TopoDS_Edge GEOMImpl_Fillet1d::Result ( const gp_Pnt &  thePoint,
TopoDS_Edge &  theEdge1,
TopoDS_Edge &  theEdge2 
)

Returns result fillet edge and modified edges as out parameters.

Definition at line 435 of file GEOMImpl_Fillet1d.cxx.

{
  TopoDS_Edge aResult;
  gp_Pnt2d aTargetPoint2d;
  Standard_Real aX, aY;
  ElSLib::PlaneParameters(myPlane->Pln().Position(), thePoint, aX, aY);
  aTargetPoint2d.SetCoord(aX, aY);

  // choose the nearest circle
  Standard_Real aDistance, aP;
  GEOMImpl_Fillet1dPoint *aNearest;
  Standard_Integer a;
  TColStd_ListIteratorOfListOfReal anIter(myResultParams);
  for(aNearest = NULL, a = 1; anIter.More(); anIter.Next(), a++)
  {
    myStartSide = (myResultOrientation.Value(a)) ? Standard_True : Standard_False;
    GEOMImpl_Fillet1dPoint *aPoint = new GEOMImpl_Fillet1dPoint(anIter.Value());
    fillPoint(aPoint);
    if (!aPoint->HasSolution(myRadius))
      continue;
    aP = fabs(aPoint->GetCenter().Distance(aTargetPoint2d) - myRadius);
    if (!aNearest || aP < aDistance)
    {
      aNearest = aPoint;
      aDistance = aP;
    }
    else
    {
      delete aPoint;
    }
   }

  if (!aNearest)
     return aResult;

  // create circle edge
  gp_Pnt aCenter = ElSLib::PlaneValue(aNearest->GetCenter().X(),
                                      aNearest->GetCenter().Y(),
                                      myPlane->Pln().Position());
  Handle(Geom_Circle) aCircle =
    new Geom_Circle(gp_Ax2(aCenter, myPlane->Pln().Axis().Direction()), myRadius);
  gp_Pnt2d aPoint2d1, aPoint2d2;
  myCurve1->D0(aNearest->GetParam(), aPoint2d1);
  myCurve2->D0(aNearest->GetParam2(), aPoint2d2);
  gp_Pnt aPoint1 = ElSLib::PlaneValue(aPoint2d1.X(), aPoint2d1.Y(), myPlane->Pln().Position());
  gp_Pnt aPoint2 = ElSLib::PlaneValue(aPoint2d2.X(), aPoint2d2.Y(), myPlane->Pln().Position());

  GeomAPI_ProjectPointOnCurve aProj(thePoint, aCircle);
  Standard_Real aTarGetParam = aProj.LowerDistanceParameter();
  gp_Pnt aPointOnCircle = aProj.NearestPoint();

  // Check extrema point manually, because there is a bug in Open CASCADE
  //  in calculation of nearest point to a circle near the parameter 0.0
  gp_Pnt p0 = ElCLib::Value(0.0, aCircle->Circ());
  if (p0.Distance(thePoint) < aPointOnCircle.Distance(thePoint))
  {
     aTarGetParam = 0.0;
     aPointOnCircle = p0;
  }

  aProj.Perform(aPoint1);
  Standard_Real aParam1 = aProj.LowerDistanceParameter();
    aProj.Perform(aPoint2);
  Standard_Real aParam2 = aProj.LowerDistanceParameter();
  Standard_Boolean aIsOut = ((aParam1 < aTarGetParam && aParam2 < aTarGetParam) ||
                             (aParam1 > aTarGetParam && aParam2 > aTarGetParam));
  if (aParam1 > aParam2)
    aIsOut = !aIsOut;
  BRepBuilderAPI_MakeEdge aBuilder(aCircle->Circ(),
                                   aIsOut ? aParam2 : aParam1,
                                   aIsOut? aParam1 : aParam2);
  aResult = aBuilder.Edge();

  // divide edges
  Standard_Real aStart, anEnd;
  Handle(Geom_Curve) aCurve = BRep_Tool::Curve(myEdge1, aStart, anEnd);
  gp_Vec aDir;
  aCurve->D1(aNearest->GetParam(), aPoint1, aDir);

  gp_Vec aCircleDir;
  aCircle->D1(aParam1, aPoint1, aCircleDir);
  if ((aCircleDir.Angle(aDir) > M_PI / 2.0) ^ aIsOut)
    aStart = aNearest->GetParam();
  else
    anEnd = aNearest->GetParam();

  if (fabs(aStart - anEnd) > Precision::Confusion())
  {
      //Divide edge
      BRepBuilderAPI_MakeEdge aDivider1(aCurve, aStart, anEnd);
      if (myEdgesExchnged)
        theEdge2 = aDivider1.Edge();
      else
        theEdge1 = aDivider1.Edge();
  }

  aCurve = BRep_Tool::Curve(myEdge2, aStart, anEnd);
  aCurve->D1(aNearest->GetParam2(), aPoint2, aDir);

  aCircle->D1(aParam2, aPoint2, aCircleDir);
  if ((aCircleDir.Angle(aDir) > M_PI / 2.0) ^ (!aIsOut))
    aStart = aNearest->GetParam2();
  else
    anEnd = aNearest->GetParam2();

  if (fabs(aStart - anEnd) > Precision::Confusion())
  {
      BRepBuilderAPI_MakeEdge aDivider2(aCurve, aStart, anEnd);
      if (myEdgesExchnged)
        theEdge1 = aDivider2.Edge();
      else
        theEdge2 = aDivider2.Edge();
  }

  delete aNearest;
  return aResult;
}

Here is the call graph for this function:

Here is the caller graph for this function:


Member Data Documentation

Definition at line 67 of file GEOMImpl_Fillet1d.hxx.

Standard_Integer GEOMImpl_Fillet1d::myDegreeOfRecursion [private]

Definition at line 72 of file GEOMImpl_Fillet1d.hxx.

TopoDS_Edge GEOMImpl_Fillet1d::myEdge1 [private]

private fields

Definition at line 65 of file GEOMImpl_Fillet1d.hxx.

TopoDS_Edge GEOMImpl_Fillet1d::myEdge2 [private]

Definition at line 65 of file GEOMImpl_Fillet1d.hxx.

Standard_Boolean GEOMImpl_Fillet1d::myEdgesExchnged [private]

Definition at line 71 of file GEOMImpl_Fillet1d.hxx.

Standard_Real GEOMImpl_Fillet1d::myEnd1 [private]

Definition at line 68 of file GEOMImpl_Fillet1d.hxx.

Standard_Real GEOMImpl_Fillet1d::myEnd2 [private]

Definition at line 68 of file GEOMImpl_Fillet1d.hxx.

Standard_Real GEOMImpl_Fillet1d::myRadius [private]

Definition at line 68 of file GEOMImpl_Fillet1d.hxx.

TColStd_SequenceOfInteger GEOMImpl_Fillet1d::myResultOrientation [private]

Definition at line 70 of file GEOMImpl_Fillet1d.hxx.

TColStd_ListOfReal GEOMImpl_Fillet1d::myResultParams [private]

Definition at line 69 of file GEOMImpl_Fillet1d.hxx.

Standard_Real GEOMImpl_Fillet1d::myStart1 [private]

Definition at line 68 of file GEOMImpl_Fillet1d.hxx.

Standard_Real GEOMImpl_Fillet1d::myStart2 [private]

Definition at line 68 of file GEOMImpl_Fillet1d.hxx.

Standard_Boolean GEOMImpl_Fillet1d::myStartSide [private]

Definition at line 71 of file GEOMImpl_Fillet1d.hxx.


The documentation for this class was generated from the following files: