Salome HOME
Cleanup code of SketchPlugin_Fillet feature. Move calculation of tangent circle to...
authorazv <azv@opencascade.com>
Sat, 1 Apr 2017 08:33:13 +0000 (11:33 +0300)
committerazv <azv@opencascade.com>
Sat, 1 Apr 2017 08:33:13 +0000 (11:33 +0300)
src/GeomAPI/GeomAPI_Circ2d.cpp
src/GeomAPI/GeomAPI_Circ2d.h
src/SketchPlugin/SketchPlugin_Fillet.cpp
src/SketchPlugin/SketchPlugin_Fillet.h

index a50e343ca11607142790e9b3a18450690d3826cb..ca6be46f31f1c892da0eb572105d70c07049a84c 100644 (file)
 #include <GeomAPI_Shape.h>
 
 #include <BRep_Tool.hxx>
+#include <ElCLib.hxx>
 #include <gp_Dir2d.hxx>
 #include <gp_Circ2d.hxx>
 #include <gp_Lin2d.hxx>
 #include <gp_Pnt2d.hxx>
 #include <gp_Ax2d.hxx>
+#include <GccAna_Circ2d2TanRad.hxx>
 #include <GccAna_Circ2d3Tan.hxx>
 #include <GccAna_Circ2dTanCen.hxx>
 #include <GccEnt.hxx>
 #define MY_CIRC2D implPtr<gp_Circ2d>()
 
 typedef std::shared_ptr<Geom2dAdaptor_Curve>  CurveAdaptorPtr;
-
+typedef std::vector< std::shared_ptr<GccEnt_QualifiedCirc> > VectorOfGccCirc;
+typedef std::vector< std::shared_ptr<GccEnt_QualifiedLin> >  VectorOfGccLine;
+
+// Provide different mechanisms to create circle:
+// * by passing points
+// * by tangent edges
+// * with specified radius
+// * etc.
 class CircleBuilder
 {
 public:
   CircleBuilder(const std::shared_ptr<GeomAPI_Ax3>& theBasePlane)
-    : myPlane(new Geom_Plane(theBasePlane->impl<gp_Ax3>()))
+    : myPlane(new Geom_Plane(theBasePlane->impl<gp_Ax3>())),
+      myRadius(0.0)
   {}
 
+  void setRadius(const double theRadius)
+  { myRadius = theRadius; }
+
   void addCenter(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter)
   { myCenter = theCenter; }
 
@@ -80,12 +93,20 @@ public:
 
   gp_Circ2d* circle()
   {
+    if (myTangentShapes.size() > 1)
+      sortTangentShapes();
+
     gp_Circ2d* aResult = 0;
     if (myCenter) {
       if (myPassingPoints.size() == 1)
         aResult = circleByCenterAndPassingPoint();
       else if (myTangentShapes.size() == 1)
         aResult = circleByCenterAndTangent();
+      else if (myRadius > 0.0)
+        aResult = circleByCenterAndRadius();
+    } else if (myRadius > 0.0) {
+      if (myTangentShapes.size() == 2)
+        aResult = circleByRadiusAndTwoTangentCurves();
     } else {
       switch (myPassingPoints.size()) {
       case 0:
@@ -108,6 +129,25 @@ public:
   }
 
 private:
+  void sortTangentShapes()
+  {
+    // sort tangent shapes, so circles go before lines
+    int aSize = (int)myTangentShapes.size();
+    for (int i = 1; i < aSize; ++i) {
+      if (myTangentShapes[i]->GetType() != GeomAbs_Circle)
+        continue;
+
+      for (int j = i - 1; j >= 0 && myTangentShapes[j]->GetType() == GeomAbs_Line; --j)
+        std::swap(myTangentShapes[j], myTangentShapes[j+1]);
+    }
+  }
+
+  gp_Circ2d* circleByCenterAndRadius()
+  {
+    const gp_Pnt2d& aCenter = myCenter->impl<gp_Pnt2d>();
+    return new gp_Circ2d(gp_Ax2d(aCenter, gp::DX2d()), myRadius);
+  }
+
   gp_Circ2d* circleByCenterAndPassingPoint()
   {
     const gp_Pnt2d& aCenter = myCenter->impl<gp_Pnt2d>();
@@ -162,31 +202,15 @@ private:
 
   gp_Circ2d* circleByThreeTangentCurves()
   {
-    std::shared_ptr<GccEnt_QualifiedCirc> aTgCirc[3];
-    std::shared_ptr<GccEnt_QualifiedLin>  aTgLine[3];
-    int aNbTgCirc = 0;
-    int aNbTgLine = 0;
+    VectorOfGccCirc aTgCirc;
+    VectorOfGccLine aTgLine;
+    convertTangentCurvesToGccEnt(aTgCirc, aTgLine);
 
-    std::vector<CurveAdaptorPtr>::iterator anIt = myTangentShapes.begin();
-    for (; anIt != myTangentShapes.end(); ++anIt) {
-      switch ((*anIt)->GetType()) {
-      case GeomAbs_Line:
-        aTgLine[aNbTgLine++] = std::shared_ptr<GccEnt_QualifiedLin>(
-            new GccEnt_QualifiedLin((*anIt)->Line(), GccEnt_unqualified));
-        break;
-      case GeomAbs_Circle:
-        aTgCirc[aNbTgCirc++] = std::shared_ptr<GccEnt_QualifiedCirc>(
-            new GccEnt_QualifiedCirc((*anIt)->Circle(), GccEnt_unqualified));
-        break;
-      default:
-        break;
-      }
-    }
-    if (aNbTgCirc + aNbTgLine != 3)
+    if (aTgCirc.size() + aTgLine.size() != 3)
       return 0;
 
     std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
-    switch (aNbTgLine) {
+    switch (aTgLine.size()) {
     case 0:
       aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
           *aTgCirc[0], *aTgCirc[1], *aTgCirc[2], Precision::Confusion()));
@@ -279,7 +303,6 @@ private:
     return 0;
   }
 
-
   gp_Circ2d* getProperCircle(const std::shared_ptr<GccAna_Circ2d3Tan>& theBuilder) const
   {
     if (!theBuilder)
@@ -318,11 +341,127 @@ private:
     return aResult;
   }
 
+
+  gp_Circ2d* circleByRadiusAndTwoTangentCurves()
+  {
+    VectorOfGccCirc aTgCirc;
+    VectorOfGccLine aTgLine;
+    convertTangentCurvesToGccEnt(aTgCirc, aTgLine);
+
+    if (aTgCirc.size() + aTgLine.size() != 2)
+      return 0;
+
+    std::shared_ptr<GccAna_Circ2d2TanRad> aCircleBuilder;
+    switch (aTgLine.size()) {
+    case 0:
+      aCircleBuilder = std::shared_ptr<GccAna_Circ2d2TanRad>(new GccAna_Circ2d2TanRad(
+          *aTgCirc[0], *aTgCirc[1], myRadius, Precision::Confusion()));
+      break;
+    case 1:
+      aCircleBuilder = std::shared_ptr<GccAna_Circ2d2TanRad>(new GccAna_Circ2d2TanRad(
+          *aTgCirc[0], *aTgLine[0], myRadius, Precision::Confusion()));
+      break;
+    case 2:
+      aCircleBuilder = std::shared_ptr<GccAna_Circ2d2TanRad>(new GccAna_Circ2d2TanRad(
+          *aTgLine[0], *aTgLine[1], myRadius, Precision::Confusion()));
+      break;
+    default:
+      break;
+    }
+
+    return getProperCircle(aCircleBuilder);
+  }
+
+  gp_Circ2d* getProperCircle(const std::shared_ptr<GccAna_Circ2d2TanRad>& theBuilder) const
+  {
+    if (!theBuilder)
+      return 0;
+
+    gp_Circ2d* aResult = 0;
+    int aNbSol = theBuilder->NbSolutions();
+    double aParSol, aPonTgCurve;
+    gp_Pnt2d aTgPnt;
+    for (int i = 1; i <= aNbSol; ++i) {
+      bool isApplicable = false;
+      if (myTangentShapes.size() >= 1) {
+        theBuilder->Tangency1(i, aParSol, aPonTgCurve, aTgPnt);
+        isApplicable = isParamInCurve(aPonTgCurve, myTangentShapes[0]);
+      }
+      if (myTangentShapes.size() >= 2 && isApplicable) {
+        theBuilder->Tangency2(i, aParSol, aPonTgCurve, aTgPnt);
+        isApplicable = isParamInCurve(aPonTgCurve, myTangentShapes[1]);
+      }
+
+      if (isApplicable) {
+        aResult = new gp_Circ2d(theBuilder->ThisSolution(i));
+        break;
+      }
+    }
+    // unable to build circle passing through the tangent curve => get any tangent point
+    if (!aResult && aNbSol > 0)
+      aResult =  new gp_Circ2d(theBuilder->ThisSolution(1));
+    return aResult;
+  }
+
+
+  void convertTangentCurvesToGccEnt(VectorOfGccCirc& theTangentCircles,
+                                    VectorOfGccLine& theTangentLines)
+  {
+    theTangentCircles.reserve(3);
+    theTangentLines.reserve(3);
+
+    std::vector<CurveAdaptorPtr>::iterator anIt = myTangentShapes.begin();
+    for (; anIt != myTangentShapes.end(); ++anIt) {
+      switch ((*anIt)->GetType()) {
+      case GeomAbs_Line:
+        theTangentLines.push_back(
+            std::shared_ptr<GccEnt_QualifiedLin>(
+            new GccEnt_QualifiedLin((*anIt)->Line(), GccEnt_unqualified))
+        );
+        break;
+      case GeomAbs_Circle:
+        theTangentCircles.push_back(
+            std::shared_ptr<GccEnt_QualifiedCirc>(
+            new GccEnt_QualifiedCirc((*anIt)->Circle(), GccEnt_unqualified))
+        );
+        break;
+      default:
+        break;
+      }
+    }
+  }
+
+
+  // boundary parameters of curve are NOT applied
+  static bool isParamInCurve(double& theParameter, const CurveAdaptorPtr& theCurve)
+  {
+    if (theCurve->Curve()->IsPeriodic()) {
+      theParameter = ElCLib::InPeriod(theParameter,
+                                      theCurve->FirstParameter(),
+                                      theCurve->FirstParameter() + theCurve->Period());
+    }
+    return theParameter > theCurve->FirstParameter() &&
+           theParameter < theCurve->LastParameter();
+  }
+
+  // boundary parameters of curve are applied too
+  static bool isParamOnCurve(double& theParameter, const CurveAdaptorPtr& theCurve)
+  {
+    if (theCurve->IsPeriodic()) {
+      theParameter = ElCLib::InPeriod(theParameter,
+                                      theCurve->FirstParameter(),
+                                      theCurve->FirstParameter() + theCurve->Period());
+    }
+    return theParameter >= theCurve->FirstParameter() &&
+           theParameter <= theCurve->LastParameter();
+  }
+
 private:
   Handle(Geom_Plane) myPlane;
   std::shared_ptr<GeomAPI_Pnt2d> myCenter;
   std::vector<gp_Pnt2d> myPassingPoints;
   std::vector<CurveAdaptorPtr> myTangentShapes;
+  double myRadius;
 };
 
 typedef std::shared_ptr<CircleBuilder> CircleBuilderPtr;
@@ -439,6 +578,19 @@ GeomAPI_Circ2d::GeomAPI_Circ2d(const std::shared_ptr<GeomAPI_Interface>& theEnti
   setImpl(aBuilder->circle());
 }
 
+GeomAPI_Circ2d::GeomAPI_Circ2d(const std::shared_ptr<GeomAPI_Interface>& theEntity1,
+                               const std::shared_ptr<GeomAPI_Interface>& theEntity2,
+                               const double                              theRadius,
+                               const std::shared_ptr<GeomAPI_Ax3>&       thePlane)
+{
+  CircleBuilderPtr aBuilder(new CircleBuilder(thePlane));
+  aBuilder->addPassingEntity(theEntity1);
+  aBuilder->addPassingEntity(theEntity2);
+  aBuilder->setRadius(theRadius);
+  setImpl(aBuilder->circle());
+}
+
+
 
 const std::shared_ptr<GeomAPI_Pnt2d> GeomAPI_Circ2d::project(
     const std::shared_ptr<GeomAPI_Pnt2d>& thePoint) const
index 0777ad3540e384c5411c1074f341a8b42d08c91a..427197a84060e1edec54394488b666450c0b04da 100644 (file)
@@ -53,6 +53,14 @@ class GeomAPI_Circ2d : public GeomAPI_Interface
                  const std::shared_ptr<GeomAPI_Interface>& theEntity3,
                  const std::shared_ptr<GeomAPI_Ax3>&       thePlane);
 
+  /// Creation of a circle with given radius passing through or tangent to two entities.
+  /// Supported items are GeomAPI_Pnt2d or GeomAPI_Shape
+  GEOMAPI_EXPORT
+  GeomAPI_Circ2d(const std::shared_ptr<GeomAPI_Interface>& theEntity1,
+                 const std::shared_ptr<GeomAPI_Interface>& theEntity2,
+                 const double                              theRadius,
+                 const std::shared_ptr<GeomAPI_Ax3>&       thePlane);
+
   /// Return center of the circle
   GEOMAPI_EXPORT
   const std::shared_ptr<GeomAPI_Pnt2d> center() const;
index 6456d7b8c922bd28ab388062375b28de8c43a38b..89b2c6df850b7135d98a066fecc551a9787a3991 100644 (file)
@@ -46,22 +46,19 @@ const double PI = 3.141592653589793238463;
 static void recalculateAttributes(FeaturePtr theNewArc, const std::string& theNewArcAttribute,
   FeaturePtr theFeature, const std::string& theFeatureAttribute);
 
+
+/// \brief Calculate radius of a fillet.
+///        It should not be greater than 1/3 of shortest edge length.
+static double calculateFilletRadius(FeaturePtr theFilletFeatures[2]);
+
 /// \brief Calculates center of fillet arc and coordinates of tangency points
-static void calculateFilletCenter(FeaturePtr theFeatureA, FeaturePtr theFeatureB,
-                                  double theRadius, bool theNotInversed[2],
+static void calculateFilletCenter(FeaturePtr theFilletFeatures[2],
+                                  double theFilletRadius,
+                                  const std::shared_ptr<GeomAPI_Ax3>& theSketchPlane,
                                   std::shared_ptr<GeomAPI_XY>& theCenter,
                                   std::shared_ptr<GeomAPI_XY>& theTangentA,
                                   std::shared_ptr<GeomAPI_XY>& theTangentB);
 
-/// Get point on 1/3 length of edge from fillet point
-static void getPointOnEdge(const FeaturePtr theFeature,
-                           const std::shared_ptr<GeomAPI_Pnt2d> theFilletPoint,
-                           std::shared_ptr<GeomAPI_Pnt2d>& thePoint);
-
-/// Get distance from point to feature
-static double getProjectionDistance(const FeaturePtr theFeature,
-                             const std::shared_ptr<GeomAPI_Pnt2d> thePoint);
-
 /// Get coincide edges for fillet
 static std::set<FeaturePtr> getCoincides(const FeaturePtr& theConstraintCoincidence);
 
@@ -233,18 +230,8 @@ bool SketchPlugin_Fillet::calculateFilletParameters()
     return false;
   }
 
-  // Getting points located at 1/3 of edge length from fillet point.
   std::shared_ptr<GeomAPI_Pnt2d> aFilletPnt2d = aFilletPoint2D->pnt();
-  std::shared_ptr<GeomAPI_Pnt2d> aPnt1, aPnt2;
-  getPointOnEdge(myBaseFeatures[0], aFilletPnt2d, aPnt1);
-  getPointOnEdge(myBaseFeatures[1], aFilletPnt2d, aPnt2);
-
-  /// Getting distances.
-  double aDistance1 = getProjectionDistance(myBaseFeatures[1], aPnt1);
-  double aDistance2 = getProjectionDistance(myBaseFeatures[0], aPnt2);
-
-  // Calculate radius value for fillet.
-  double aRadius = aDistance1 < aDistance2 ? aDistance1 / 2.0 : aDistance2 / 2.0;
+  double aRadius = calculateFilletRadius(myBaseFeatures);
 
   // Calculate arc attributes.
   static const int aNbFeatures = 2;
@@ -277,8 +264,9 @@ bool SketchPlugin_Fillet::calculateFilletParameters()
       }
   }
 
-  calculateFilletCenter(myBaseFeatures[0], myBaseFeatures[1], aRadius,
-      myIsNotInversed, myCenterXY, myTangentXY1, myTangentXY2);
+  std::shared_ptr<GeomAPI_Ax3> aSketchPlane = SketchPlugin_Sketch::plane(sketch());
+  calculateFilletCenter(myBaseFeatures, aRadius, aSketchPlane,
+                        myCenterXY, myTangentXY1, myTangentXY2);
 
   // Tangent directions of the features in coincident point.
   std::shared_ptr<GeomAPI_Dir2d> aTangentDir[aNbFeatures];
@@ -376,351 +364,84 @@ void recalculateAttributes(FeaturePtr theNewArc,  const std::string& theNewArcAt
       theFeature->attribute(theFeatureAttribute))->setValue(anArcPoint->x(), anArcPoint->y());
 }
 
-/// \brief Find intersections of lines shifted along normal direction
-void possibleFilletCenterLineLine(
-    std::shared_ptr<GeomAPI_XY> thePointA, std::shared_ptr<GeomAPI_Dir2d> theDirA,
-    std::shared_ptr<GeomAPI_XY> thePointB, std::shared_ptr<GeomAPI_Dir2d> theDirB,
-    double theRadius, std::list< std::shared_ptr<GeomAPI_XY> >& theCenters)
+static std::shared_ptr<GeomAPI_Pnt2d> toPoint(const AttributePtr& theAttribute)
 {
-  std::shared_ptr<GeomAPI_Dir2d> aDirAT(new GeomAPI_Dir2d(-theDirA->y(), theDirA->x()));
-  std::shared_ptr<GeomAPI_Dir2d> aDirBT(new GeomAPI_Dir2d(-theDirB->y(), theDirB->x()));
-  std::shared_ptr<GeomAPI_XY> aPntA, aPntB;
-  double aDet = theDirA->cross(theDirB);
-  for (double aStepA = -1.0; aStepA <= 1.0; aStepA += 2.0) {
-    aPntA = thePointA->added(aDirAT->xy()->multiplied(aStepA * theRadius));
-    for (double aStepB = -1.0; aStepB <= 1.0; aStepB += 2.0) {
-      aPntB = thePointB->added(aDirBT->xy()->multiplied(aStepB * theRadius));
-      double aVX = aDirAT->xy()->dot(aPntA);
-      double aVY = aDirBT->xy()->dot(aPntB);
-      std::shared_ptr<GeomAPI_XY> aPoint(new GeomAPI_XY(
-          (theDirB->x() * aVX - theDirA->x() * aVY) / aDet,
-          (theDirB->y() * aVX - theDirA->y() * aVY) / aDet));
-      theCenters.push_back(aPoint);
-    }
-  }
+  std::shared_ptr<GeomAPI_Pnt2d> aPoint;
+  AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
+  if (aPointAttr)
+    aPoint = aPointAttr->pnt();
+  return aPoint;
 }
 
-/// \brief Find intersections of line shifted along normal direction in both sides
-///        and a circle with extended radius
-void possibleFilletCenterLineArc(
-    std::shared_ptr<GeomAPI_XY> theStartLine, std::shared_ptr<GeomAPI_Dir2d> theDirLine,
-    std::shared_ptr<GeomAPI_XY> theCenterArc, double theRadiusArc,
-    double theRadius, std::list< std::shared_ptr<GeomAPI_XY> >& theCenters)
+static std::shared_ptr<GeomAPI_Lin2d> toLine(const FeaturePtr& theFeature)
 {
-  std::shared_ptr<GeomAPI_Dir2d> aDirT(new GeomAPI_Dir2d(-theDirLine->y(), theDirLine->x()));
-  std::shared_ptr<GeomAPI_XY> aPnt;
-  double aDirNorm2 = theDirLine->dot(theDirLine);
-  double aRad = 0.0;
-  double aDirX = theDirLine->x();
-  double aDirX2 = theDirLine->x() * theDirLine->x();
-  double aDirY2 = theDirLine->y() * theDirLine->y();
-  double aDirXY = theDirLine->x() * theDirLine->y();
-  for (double aStepA = -1.0; aStepA <= 1.0; aStepA += 2.0) {
-    aPnt = theStartLine->added(aDirT->xy()->multiplied(aStepA * theRadius));
-    double aCoeff = aDirT->xy()->dot(aPnt->decreased(theCenterArc));
-    double aCoeff2 = aCoeff * aCoeff;
-    for (double aStepB = -1.0; aStepB <= 1.0; aStepB += 2.0) {
-      aRad = theRadiusArc + aStepB * theRadius;
-      double aD = aRad * aRad * aDirNorm2 - aCoeff2;
-      if (aD < 0.0)
-        continue;
-      double aDs = sqrt(aD);
-      double x1 = theCenterArc->x() + (aCoeff * aDirT->x() - aDirT->y() * aDs) / aDirNorm2;
-      double x2 = theCenterArc->x() + (aCoeff * aDirT->x() + aDirT->y() * aDs) / aDirNorm2;
-      double y1 = (aDirX2 * aPnt->y() + aDirY2 * theCenterArc->y() -
-          aDirXY * (aPnt->x() - theCenterArc->x()) - theDirLine->y() * aDs) / aDirNorm2;
-      double y2 = (aDirX2 * aPnt->y() + aDirY2 * theCenterArc->y() -
-          aDirXY * (aPnt->x() - theCenterArc->x()) + theDirLine->y() * aDs) / aDirNorm2;
-
-      std::shared_ptr<GeomAPI_XY> aPoint1(new GeomAPI_XY(x1, y1));
-      theCenters.push_back(aPoint1);
-      std::shared_ptr<GeomAPI_XY> aPoint2(new GeomAPI_XY(x2, y2));
-      theCenters.push_back(aPoint2);
-    }
+  std::shared_ptr<GeomAPI_Lin2d> aLine;
+  if (theFeature->getKind() == SketchPlugin_Line::ID()) {
+    std::shared_ptr<GeomAPI_Pnt2d> aStart =
+        toPoint( theFeature->attribute(SketchPlugin_Line::START_ID()) );
+    std::shared_ptr<GeomAPI_Pnt2d> aEnd =
+        toPoint( theFeature->attribute(SketchPlugin_Line::END_ID()) );
+    aLine = std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aStart, aEnd));
   }
+  return aLine;
 }
 
-/// \brief Find intersections of two circles with extended radii
-void possibleFilletCenterArcArc(
-    std::shared_ptr<GeomAPI_XY> theCenterA, double theRadiusA,
-    std::shared_ptr<GeomAPI_XY> theCenterB, double theRadiusB,
-    double theRadius, std::list< std::shared_ptr<GeomAPI_XY> >& theCenters)
+static std::shared_ptr<GeomAPI_Circ2d> toCircle(const FeaturePtr& theFeature)
 {
-  std::shared_ptr<GeomAPI_XY> aCenterDir = theCenterB->decreased(theCenterA);
-  double aCenterDist2 = aCenterDir->dot(aCenterDir);
-  double aCenterDist = sqrt(aCenterDist2);
-
-  double aRadA, aRadB;
-  for (double aStepA = -1.0; aStepA <= 1.0; aStepA += 2.0) {
-    aRadA = theRadiusA + aStepA * theRadius;
-    for (double aStepB = -1.0; aStepB <= 1.0; aStepB += 2.0) {
-      aRadB = theRadiusB + aStepB * theRadius;
-      if (aRadA + aRadB < aCenterDist || fabs(aRadA - aRadB) > aCenterDist)
-        continue; // there is no intersections
-
-      double aMedDist = (aRadA * aRadA - aRadB * aRadB + aCenterDist2) / (2.0 * aCenterDist);
-      double aHeight = sqrt(aRadA * aRadA - aMedDist * aMedDist);
-
-      double x1 = theCenterA->x() +
-        (aMedDist * aCenterDir->x() + aCenterDir->y() * aHeight) / aCenterDist;
-      double y1 = theCenterA->y() +
-        (aMedDist * aCenterDir->y() - aCenterDir->x() * aHeight) / aCenterDist;
-
-      double x2 = theCenterA->x() +
-        (aMedDist * aCenterDir->x() - aCenterDir->y() * aHeight) / aCenterDist;
-      double y2 = theCenterA->y() +
-        (aMedDist * aCenterDir->y() + aCenterDir->x() * aHeight) / aCenterDist;
-
-      std::shared_ptr<GeomAPI_XY> aPoint1(new GeomAPI_XY(x1, y1));
-      theCenters.push_back(aPoint1);
-      std::shared_ptr<GeomAPI_XY> aPoint2(new GeomAPI_XY(x2, y2));
-      theCenters.push_back(aPoint2);
-    }
+  std::shared_ptr<GeomAPI_Circ2d> aCircle;
+  if (theFeature->getKind() == SketchPlugin_Arc::ID()) {
+    std::shared_ptr<GeomAPI_Pnt2d> aCenter =
+        toPoint( theFeature->attribute(SketchPlugin_Arc::CENTER_ID()) );
+    std::shared_ptr<GeomAPI_Pnt2d> aStart =
+        toPoint( theFeature->attribute(SketchPlugin_Arc::START_ID()) );
+    aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aStart));
   }
+  return aCircle;
 }
 
-void calculateFilletCenter(FeaturePtr theFeatureA, FeaturePtr theFeatureB,
-                           double theRadius, bool theNotInversed[2],
+
+void calculateFilletCenter(FeaturePtr theFilletFeatures[2],
+                           double theFilletRadius,
+                           const std::shared_ptr<GeomAPI_Ax3>& theSketchPlane,
                            std::shared_ptr<GeomAPI_XY>& theCenter,
                            std::shared_ptr<GeomAPI_XY>& theTangentA,
                            std::shared_ptr<GeomAPI_XY>& theTangentB)
 {
-  static const int aNbFeatures = 2;
-  FeaturePtr aFeature[aNbFeatures] = {theFeatureA, theFeatureB};
-  std::shared_ptr<GeomAPI_XY> aStart[aNbFeatures], aEnd[aNbFeatures], aCenter[aNbFeatures];
-  std::shared_ptr<GeomDataAPI_Point2D> aStartPoint, aEndPoint;
-
-  for (int i = 0; i < aNbFeatures; i++) {
-    if (aFeature[i]->getKind() == SketchPlugin_Line::ID()) {
-      aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-          aFeature[i]->attribute(SketchPlugin_Line::START_ID()));
-      aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-          aFeature[i]->attribute(SketchPlugin_Line::END_ID()));
-    } else if (aFeature[i]->getKind() == SketchPlugin_Arc::ID()) {
-      aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-          aFeature[i]->attribute(SketchPlugin_Arc::START_ID()));
-      aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-          aFeature[i]->attribute(SketchPlugin_Arc::END_ID()));
-      aCenter[i] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-          aFeature[i]->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt()->xy();
-    } else
-      return;
-    aStart[i] = std::shared_ptr<GeomAPI_XY>(theNotInversed[i] ?
-        new GeomAPI_XY(aStartPoint->x(), aStartPoint->y()) :
-        new GeomAPI_XY(aEndPoint->x(), aEndPoint->y()));
-    aEnd[i] = std::shared_ptr<GeomAPI_XY>(theNotInversed[i] ?
-        new GeomAPI_XY(aEndPoint->x(), aEndPoint->y()) :
-        new GeomAPI_XY(aStartPoint->x(), aStartPoint->y()));
-  }
-
-  if (theFeatureA->getKind() == SketchPlugin_Line::ID() &&
-      theFeatureB->getKind() == SketchPlugin_Line::ID()) {
-    std::shared_ptr<GeomAPI_Dir2d> aDir[2];
-    std::shared_ptr<GeomAPI_Dir2d> aDirT[2];
-    for (int i = 0; i < aNbFeatures; i++) {
-      aDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aEnd[i]->decreased(aStart[i])));
-      aDirT[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(-aDir[i]->y(), aDir[i]->x()));
+  GeomShapePtr aShapeA = theFilletFeatures[0]->lastResult()->shape();
+  GeomShapePtr aShapeB = theFilletFeatures[1]->lastResult()->shape();
+
+  std::shared_ptr<GeomAPI_Circ2d> aFilletCircle(
+      new GeomAPI_Circ2d(aShapeA, aShapeB, theFilletRadius, theSketchPlane));
+  if (!aFilletCircle->implPtr<char>())
+    return;
+
+  theCenter = aFilletCircle->center()->xy();
+  // tangent points
+  std::shared_ptr<GeomAPI_Pnt2d> aTgPoints[2];
+  for (int i = 0; i < 2; ++i) {
+    std::shared_ptr<GeomAPI_Circ2d> aCircle = toCircle(theFilletFeatures[i]);
+    if (aCircle)
+      aTgPoints[i] = aCircle->project(aFilletCircle->center());
+    else {
+      std::shared_ptr<GeomAPI_Lin2d> aLine = toLine(theFilletFeatures[i]);
+      if (aLine)
+        aTgPoints[i] = aLine->project(aFilletCircle->center());
     }
-
-    // get and filter possible centers
-    std::list< std::shared_ptr<GeomAPI_XY> > aSuspectCenters;
-    possibleFilletCenterLineLine(aStart[0], aDir[0], aStart[1], aDir[1],
-                                 theRadius, aSuspectCenters);
-    double aDot = 0.0;
-    std::list< std::shared_ptr<GeomAPI_XY> >::iterator anIt = aSuspectCenters.begin();
-    for (; anIt != aSuspectCenters.end(); anIt++) {
-      aDot = aDirT[0]->xy()->dot(aStart[0]->decreased(*anIt));
-      theTangentA = (*anIt)->added(aDirT[0]->xy()->multiplied(aDot));
-      if (theTangentA->decreased(aStart[0])->dot(aDir[0]->xy()) < 0.0)
-        continue; // incorrect position
-      aDot = aDirT[1]->xy()->dot(aStart[1]->decreased(*anIt));
-      theTangentB = (*anIt)->added(aDirT[1]->xy()->multiplied(aDot));
-      if (theTangentB->decreased(aStart[1])->dot(aDir[1]->xy()) < 0.0)
-        continue; // incorrect position
-      // the center is found, stop searching
-      theCenter = *anIt;
-      return;
-    }
-  } else if ((theFeatureA->getKind() == SketchPlugin_Arc::ID() &&
-      theFeatureB->getKind() == SketchPlugin_Line::ID()) ||
-      (theFeatureA->getKind() == SketchPlugin_Line::ID() &&
-      theFeatureB->getKind() == SketchPlugin_Arc::ID())) {
-    int aLineInd = theFeatureA->getKind() == SketchPlugin_Line::ID() ? 0 : 1;
-    double anArcRadius = aStart[1-aLineInd]->distance(aCenter[1-aLineInd]);
-    std::shared_ptr<GeomAPI_Dir2d> aDirLine = std::shared_ptr<GeomAPI_Dir2d>(
-        new GeomAPI_Dir2d(aEnd[aLineInd]->decreased(aStart[aLineInd])));
-    std::shared_ptr<GeomAPI_Dir2d> aDirT = std::shared_ptr<GeomAPI_Dir2d>(
-        new GeomAPI_Dir2d(-aDirLine->y(), aDirLine->x()));
-
-    std::shared_ptr<GeomAPI_Dir2d> aStartArcDir = std::shared_ptr<GeomAPI_Dir2d>(
-        new GeomAPI_Dir2d(aStart[1-aLineInd]->decreased(aCenter[1-aLineInd])));
-    std::shared_ptr<GeomAPI_Dir2d> aEndArcDir = std::shared_ptr<GeomAPI_Dir2d>(
-        new GeomAPI_Dir2d(aEnd[1-aLineInd]->decreased(aCenter[1-aLineInd])));
-    double anArcAngle = aStartArcDir->angle(aEndArcDir);
-    if (anArcAngle < 0.0)
-      anArcAngle += 2.0 * PI;
-
-    // get possible centers and filter them
-    std::list< std::shared_ptr<GeomAPI_XY> > aSuspectCenters;
-    possibleFilletCenterLineArc(aStart[aLineInd], aDirLine, aCenter[1-aLineInd],
-                                anArcRadius, theRadius, aSuspectCenters);
-    double aDot = 0.0;
-    // the line is forward into the arc
-    double innerArc = aCenter[1-aLineInd]->decreased(aStart[aLineInd])->dot(aDirLine->xy());
-    std::shared_ptr<GeomAPI_XY> aLineTgPoint, anArcTgPoint;
-    // The possible centers are ranged by their positions.
-    // If the point is not satisfy one of criteria, the weight is decreased with penalty.
-    int aBestWeight = 0;
-    std::list< std::shared_ptr<GeomAPI_XY> >::iterator anIt = aSuspectCenters.begin();
-    for (; anIt != aSuspectCenters.end(); anIt++) {
-      int aWeight = 2;
-      aDot = aDirT->xy()->dot(aStart[aLineInd]->decreased(*anIt));
-      aLineTgPoint = (*anIt)->added(aDirT->xy()->multiplied(aDot));
-      // Check the point is placed on the correct arc (penalty if false)
-      if (aCenter[1-aLineInd]->distance(*anIt) * innerArc > anArcRadius * innerArc)
-        aWeight -= 1;
-      std::shared_ptr<GeomAPI_Dir2d> aCurDir = std::shared_ptr<GeomAPI_Dir2d>(
-          new GeomAPI_Dir2d((*anIt)->decreased(aCenter[1-aLineInd])));
-      double aCurAngle = aStartArcDir->angle(aCurDir);
-      if (aCurAngle < 0.0)
-        aCurAngle += 2.0 * PI;
-      if (aCurAngle < 0.0 || aCurAngle > anArcAngle)
-        continue;
-      if (aWeight > aBestWeight)
-        aBestWeight = aWeight;
-      else if (aWeight < aBestWeight ||
-               aStart[aLineInd]->distance(*anIt) >
-               aStart[aLineInd]->distance(theCenter)) // <-- take closer point
-        continue;
-      // the center is found, stop searching
-      theCenter = *anIt;
-      anArcTgPoint = aCenter[1-aLineInd]->added(aCurDir->xy()->multiplied(anArcRadius));
-      if (theFeatureA->getKind() == SketchPlugin_Line::ID()) {
-        theTangentA = aLineTgPoint;
-        theTangentB = anArcTgPoint;
-      } else {
-        theTangentA = anArcTgPoint;
-        theTangentB = aLineTgPoint;
-      }
-      //return;
-    }
-  } else if (theFeatureA->getKind() == SketchPlugin_Arc::ID() &&
-      theFeatureB->getKind() == SketchPlugin_Arc::ID()) {
-    double anArcRadius[aNbFeatures];
-    double anArcAngle[aNbFeatures];
-    std::shared_ptr<GeomAPI_Dir2d> aStartArcDir[aNbFeatures];
-    for (int i = 0; i < aNbFeatures; i++) {
-      anArcRadius[i] = aStart[i]->distance(aCenter[i]);
-      aStartArcDir[i] = std::shared_ptr<GeomAPI_Dir2d>(
-          new GeomAPI_Dir2d(aStart[i]->decreased(aCenter[i])));
-      std::shared_ptr<GeomAPI_Dir2d> aEndArcDir = std::shared_ptr<GeomAPI_Dir2d>(
-          new GeomAPI_Dir2d(aEnd[i]->decreased(aCenter[i])));
-      anArcAngle[i] = aStartArcDir[i]->angle(aEndArcDir);
-      if (anArcAngle[i] < 0.0)
-        anArcAngle[i] += 2.0 * PI;
-    }
-
-    // get and filter possible centers
-    std::list< std::shared_ptr<GeomAPI_XY> > aSuspectCenters;
-    possibleFilletCenterArcArc(aCenter[0], anArcRadius[0], aCenter[1],
-                               anArcRadius[1], theRadius, aSuspectCenters);
-    double aDot = 0.0;
-    std::shared_ptr<GeomAPI_XY> aLineTgPoint, anArcTgPoint;
-    std::list< std::shared_ptr<GeomAPI_XY> >::iterator anIt = aSuspectCenters.begin();
-    for (; anIt != aSuspectCenters.end(); anIt++) {
-      std::shared_ptr<GeomAPI_Dir2d> aCurDir = std::shared_ptr<GeomAPI_Dir2d>(
-          new GeomAPI_Dir2d((*anIt)->decreased(aCenter[0])));
-      double aCurAngle = aStartArcDir[0]->angle(aCurDir);
-      if (aCurAngle < 0.0)
-          aCurAngle += 2.0 * PI;
-      if (aCurAngle < 0.0 || aCurAngle > anArcAngle[0])
-        continue; // incorrect position
-      theTangentA = aCenter[0]->added(aCurDir->xy()->multiplied(anArcRadius[0]));
-
-      aCurDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d((*anIt)->decreased(aCenter[1])));
-      aCurAngle = aStartArcDir[1]->angle(aCurDir);
-      if (aCurAngle < 0.0)
-          aCurAngle += 2.0 * PI;
-      if (aCurAngle < 0.0 || aCurAngle > anArcAngle[1])
-        continue; // incorrect position
-      theTangentB = aCenter[1]->added(aCurDir->xy()->multiplied(anArcRadius[1]));
-
-      // the center is found, stop searching
-      theCenter = *anIt;
-      return;
-    }
-  }
-}
-
-void getPointOnEdge(const FeaturePtr theFeature,
-                    const std::shared_ptr<GeomAPI_Pnt2d> theFilletPoint,
-                    std::shared_ptr<GeomAPI_Pnt2d>& thePoint) {
-  if(theFeature->getKind() == SketchPlugin_Line::ID()) {
-    std::shared_ptr<GeomAPI_Pnt2d> aPntStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theFeature->attribute(SketchPlugin_Line::START_ID()))->pnt();
-    std::shared_ptr<GeomAPI_Pnt2d> aPntEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theFeature->attribute(SketchPlugin_Line::END_ID()))->pnt();
-    if(aPntStart->distance(theFilletPoint) > 1.e-7) {
-      aPntStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-        theFeature->attribute(SketchPlugin_Line::END_ID()))->pnt();
-      aPntEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-        theFeature->attribute(SketchPlugin_Line::START_ID()))->pnt();
-    }
-    thePoint.reset(
-      new GeomAPI_Pnt2d(aPntStart->xy()->added(
-      aPntEnd->xy()->decreased( aPntStart->xy() )->multiplied(1.0 / 3.0) ) ) );
-  } else {
-    std::shared_ptr<GeomAPI_Pnt2d> aPntTemp;
-    std::shared_ptr<GeomAPI_Pnt2d> aPntStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theFeature->attribute(SketchPlugin_Arc::START_ID()))->pnt();
-    std::shared_ptr<GeomAPI_Pnt2d> aPntEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theFeature->attribute(SketchPlugin_Arc::END_ID()))->pnt();
-    if(theFeature->boolean(SketchPlugin_Arc::REVERSED_ID())->value()) {
-      aPntTemp = aPntStart;
-      aPntStart = aPntEnd;
-      aPntEnd = aPntTemp;
-    }
-    std::shared_ptr<GeomAPI_Pnt2d> aCenterPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
-    std::shared_ptr<GeomAPI_Circ2d> aCirc(new GeomAPI_Circ2d(aCenterPnt, aPntStart));
-    double aStartParameter(0), anEndParameter(0);
-    aCirc->parameter(aPntStart, paramTolerance, aStartParameter);
-    aCirc->parameter(aPntEnd, paramTolerance, anEndParameter);
-    if(aPntStart->distance(theFilletPoint) > tolerance) {
-      double aTmpParameter = aStartParameter;
-      aStartParameter = anEndParameter;
-      anEndParameter = aTmpParameter;
-    }
-    double aPntParameter = aStartParameter + (anEndParameter - aStartParameter) / 3.0;
-    aCirc->D0(aPntParameter, thePoint);
   }
+  theTangentA = aTgPoints[0]->xy();
+  theTangentB = aTgPoints[1]->xy();
 }
 
-double getProjectionDistance(const FeaturePtr theFeature,
-                             const std::shared_ptr<GeomAPI_Pnt2d> thePoint)
+double calculateFilletRadius(FeaturePtr theFilletFeatures[2])
 {
-  std::shared_ptr<GeomAPI_Pnt2d> aProjectPnt;
-  if(theFeature->getKind() == SketchPlugin_Line::ID()) {
-    std::shared_ptr<GeomAPI_Pnt2d> aPntStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theFeature->attribute(SketchPlugin_Line::START_ID()))->pnt();
-    std::shared_ptr<GeomAPI_Pnt2d> aPntEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theFeature->attribute(SketchPlugin_Line::END_ID()))->pnt();
-    std::shared_ptr<GeomAPI_Lin2d> aLin(new GeomAPI_Lin2d(aPntStart, aPntEnd));
-    aProjectPnt = aLin->project(thePoint);
-  } else {
-    std::shared_ptr<GeomAPI_Pnt2d> aPntStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theFeature->attribute(SketchPlugin_Arc::START_ID()))->pnt();
-    std::shared_ptr<GeomAPI_Pnt2d> aPntEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theFeature->attribute(SketchPlugin_Arc::END_ID()))->pnt();
-    std::shared_ptr<GeomAPI_Pnt2d> aCenterPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
-    std::shared_ptr<GeomAPI_Circ2d> aCirc(new GeomAPI_Circ2d(aCenterPnt, aPntStart));
-    aProjectPnt = aCirc->project(thePoint);
-  }
-  if(aProjectPnt.get()) {
-    return aProjectPnt->distance(thePoint);
+  double aLengths[2] = { 0, 0 };
+  for (int i = 0; i < 2; ++i) {
+    GeomShapePtr aShape = theFilletFeatures[i]->lastResult()->shape();
+    std::shared_ptr<GeomAPI_Edge> anEdge = std::dynamic_pointer_cast<GeomAPI_Edge>(aShape);
+    if (anEdge)
+      aLengths[i] = anEdge->length();
   }
-  return -1;
+  return std::min(aLengths[0], aLengths[1]) / 6.0;
 }
 
 std::set<FeaturePtr> getCoincides(const FeaturePtr& theConstraintCoincidence)
index 49388f26a5aad2382cf7ec1ac1ae015b428027f7..7cee33ca4b6af7a17468aaa85c7ba4c00edaa566 100644 (file)
@@ -55,13 +55,13 @@ class SketchPlugin_Fillet: public SketchPlugin_SketchEntity, public GeomAPI_IPre
 
   /// Reimplemented from ModelAPI_Feature::isMacro().
   /// \returns true
-  SKETCHPLUGIN_EXPORT virtual bool isMacro() const {return true;};
+  SKETCHPLUGIN_EXPORT virtual bool isMacro() const {return true;}
 
-  SKETCHPLUGIN_EXPORT virtual bool isPreviewNeeded() const {return false;};
+  SKETCHPLUGIN_EXPORT virtual bool isPreviewNeeded() const {return false;}
 
   /// Reimplemented from SketchPlugin_Feature::move().
   /// Do nothing.
-  SKETCHPLUGIN_EXPORT virtual void move(const double theDeltaX, const double theDeltaY) {};
+  SKETCHPLUGIN_EXPORT virtual void move(const double, const double) {}
 
   /// \brief Use plugin manager for features creation
   SketchPlugin_Fillet();