Salome HOME
Issue #2024: Redesign of circle and arc of circle
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_MacroCircle.cpp
index 375fec58813de9bd1457a0d19192ca2d23130620..7232a6c37fac9462dbdc21e355d865beabbc1c0b 100644 (file)
@@ -7,29 +7,25 @@
 #include "SketchPlugin_MacroCircle.h"
 
 #include "SketchPlugin_Circle.h"
-//#include "SketchPlugin_ConstraintCoincidence.h"
 #include "SketchPlugin_Point.h"
 #include "SketchPlugin_Tools.h"
 
-#include <ModelAPI_Data.h>
-#include <ModelAPI_Events.h>
-#include <ModelAPI_ResultConstruction.h>
-#include <ModelAPI_AttributeSelection.h>
-#include <ModelAPI_Validator.h>
 #include <ModelAPI_AttributeDouble.h>
 #include <ModelAPI_AttributeRefAttr.h>
 #include <ModelAPI_AttributeString.h>
 #include <ModelAPI_Session.h>
+#include <ModelAPI_Validator.h>
+
+#include <GeomDataAPI_Dir.h>
+#include <GeomDataAPI_Point2D.h>
 
+#include <GeomAPI_Circ2d.h>
 #include <GeomAPI_Pnt2d.h>
-#include <GeomAPI_Circ.h>
 #include <GeomAPI_Vertex.h>
-#include <GeomAPI_XY.h>
-#include <GeomDataAPI_Point2D.h>
-#include <GeomDataAPI_Dir.h>
-#include <GeomAlgoAPI_PointBuilder.h>
-#include <GeomAlgoAPI_EdgeBuilder.h>
+
 #include <GeomAlgoAPI_CompoundBuilder.h>
+#include <GeomAlgoAPI_EdgeBuilder.h>
+#include <GeomAlgoAPI_PointBuilder.h>
 
 
 const double tolerance = 1e-7;
@@ -38,9 +34,9 @@ namespace {
   static const std::string& POINT_ID(int theIndex)
   {
     switch (theIndex) {
-    case 1: return SketchPlugin_MacroCircle::FIRST_POINT_ID();
-    case 2: return SketchPlugin_MacroCircle::SECOND_POINT_ID();
-    case 3: return SketchPlugin_MacroCircle::THIRD_POINT_ID();
+      case 1: return SketchPlugin_MacroCircle::FIRST_POINT_ID();
+      case 2: return SketchPlugin_MacroCircle::SECOND_POINT_ID();
+      case 3: return SketchPlugin_MacroCircle::THIRD_POINT_ID();
     }
 
     static const std::string DUMMY;
@@ -50,8 +46,7 @@ namespace {
 
 
 SketchPlugin_MacroCircle::SketchPlugin_MacroCircle()
-: SketchPlugin_SketchEntity(),
-myRadius(0)
+: SketchPlugin_SketchEntity()
 {
 }
 
@@ -88,101 +83,41 @@ void SketchPlugin_MacroCircle::execute()
     createCircleByCenterAndPassed();
   else if (aType == CIRCLE_TYPE_BY_THREE_POINTS())
     createCircleByThreePoints();
-
-  myCenter.reset();
-  myRadius = 0;
-}
-
-static void convertToPointOrTangent(const AttributeRefAttrPtr&      theRefAttr,
-                                    const AttributePtr&             theBaseAttr,
-                                    std::shared_ptr<GeomAPI_Pnt2d>& thePassingPoint,
-                                    std::shared_ptr<GeomAPI_Shape>& theTangentCurve)
-{
-  AttributePtr anAttr = theBaseAttr;
-  if (theRefAttr->isObject()) {
-    FeaturePtr aTgFeature = ModelAPI_Feature::feature(theRefAttr->object());
-    if (aTgFeature) {
-      if (aTgFeature->getKind() != SketchPlugin_Point::ID()) {
-        theTangentCurve = aTgFeature->lastResult()->shape();
-        return;
-      }
-      anAttr = aTgFeature->attribute(SketchPlugin_Point::COORD_ID());
-    }
-  } else
-    anAttr = theRefAttr->attr();
-
-  thePassingPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr)->pnt();
 }
 
 void SketchPlugin_MacroCircle::createCircleByCenterAndPassed()
 {
-  AttributePtr aPassedAttr = attribute(PASSED_POINT_ID());
-  AttributeRefAttrPtr aPassedRef = refattr(PASSED_POINT_REF_ID());
-  // Calculate circle parameters
-  std::shared_ptr<GeomAPI_Pnt2d> aCenter =
-      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_POINT_ID()))->pnt();
-  std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
-  std::shared_ptr<GeomAPI_Shape> aTangentCurve;
-  convertToPointOrTangent(aPassedRef, aPassedAttr, aPassedPoint, aTangentCurve);
-
-  // Build a circle
-  std::shared_ptr<GeomAPI_Circ2d> aCircle;
-  if (aTangentCurve) {
-    std::shared_ptr<GeomAPI_Ax3> anAxis = SketchPlugin_Sketch::plane(sketch());
-    aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aTangentCurve, anAxis));
-  } else
-    aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aPassedPoint));
-
   // Create circle feature.
+  std::shared_ptr<GeomAPI_Circ2d> aCircle = shapeByCenterAndPassed();
   FeaturePtr aCircleFeature = createCircleFeature(aCircle);
 
   // Create constraints.
   SketchPlugin_Tools::createConstraint(this,
                                        CENTER_POINT_REF_ID(),
                                        aCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
-                                       NULL,
+                                       ObjectPtr(),
                                        false);
   SketchPlugin_Tools::createConstraint(this,
                                        PASSED_POINT_REF_ID(),
-                                       NULL,
+                                       AttributePtr(),
                                        aCircleFeature->lastResult(),
                                        true);
 }
 
 void SketchPlugin_MacroCircle::createCircleByThreePoints()
 {
-  std::string aPointAttr[3] = { FIRST_POINT_ID(),
-                                SECOND_POINT_ID(),
-                                THIRD_POINT_ID() };
   std::string aPointRef[3] = { FIRST_POINT_REF_ID(),
                                SECOND_POINT_REF_ID(),
                                THIRD_POINT_REF_ID() };
-  std::shared_ptr<GeomAPI_Interface> aPassedEntities[3];
-  for (int i = 0; i < 3; ++i) {
-    AttributePtr aPassedAttr = attribute(aPointAttr[i]);
-    AttributeRefAttrPtr aPassedRef = refattr(aPointRef[i]);
-    // calculate circle parameters
-    std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
-    std::shared_ptr<GeomAPI_Shape> aTangentCurve;
-    convertToPointOrTangent(aPassedRef, aPassedAttr, aPassedPoint, aTangentCurve);
-
-    if (aPassedPoint)
-      aPassedEntities[i] = aPassedPoint;
-    else
-      aPassedEntities[i] = aTangentCurve;
-  }
-
-  std::shared_ptr<GeomAPI_Ax3> anAxis = SketchPlugin_Sketch::plane(sketch());
-  std::shared_ptr<GeomAPI_Circ2d> aCircle = std::shared_ptr<GeomAPI_Circ2d>(
-      new GeomAPI_Circ2d(aPassedEntities[0], aPassedEntities[1], aPassedEntities[2], anAxis));
 
   // Create circle feature.
+  std::shared_ptr<GeomAPI_Circ2d> aCircle = shapeByThreePoints();
   FeaturePtr aCircleFeature = createCircleFeature(aCircle);
   ResultPtr aCircleResult = aCircleFeature->lastResult();
 
   // Create constraints.
   for (int i = 0; i < 3; ++i)
-    SketchPlugin_Tools::createConstraint(this, aPointRef[i], NULL, aCircleResult, true);
+    SketchPlugin_Tools::createConstraint(this, aPointRef[i], AttributePtr(), aCircleResult, true);
 }
 
 FeaturePtr SketchPlugin_MacroCircle::createCircleFeature(
@@ -200,24 +135,150 @@ FeaturePtr SketchPlugin_MacroCircle::createCircleFeature(
   return aCircleFeature;
 }
 
-AISObjectPtr SketchPlugin_MacroCircle::getAISObject(AISObjectPtr thePrevious)
+std::shared_ptr<GeomAPI_Circ2d> SketchPlugin_MacroCircle::shapeByCenterAndPassed()
 {
-  if(!myCenter.get() || myRadius < tolerance) {
-    return AISObjectPtr();
+  AttributePtr aCenterAttr = attribute(CENTER_POINT_ID());
+  AttributePtr aPassedAttr = attribute(PASSED_POINT_ID());
+  if (!aCenterAttr->isInitialized() || !aPassedAttr->isInitialized())
+    return std::shared_ptr<GeomAPI_Circ2d>();
+
+  AttributeRefAttrPtr aPassedRef = refattr(PASSED_POINT_REF_ID());
+  // Calculate circle parameters
+  std::shared_ptr<GeomAPI_Pnt2d> aCenter =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aCenterAttr)->pnt();
+  std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
+  std::shared_ptr<GeomAPI_Shape> aTangentCurve;
+  SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
+      aPassedRef, aPassedAttr, aTangentCurve, aPassedPoint);
+
+  // Build a circle
+  std::shared_ptr<GeomAPI_Circ2d> aCircle;
+  if (aTangentCurve) {
+    std::shared_ptr<GeomAPI_Ax3> anAxis = SketchPlugin_Sketch::plane(sketch());
+    aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aTangentCurve, anAxis));
+  } else
+    aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aPassedPoint));
+  return aCircle;
+}
+
+std::shared_ptr<GeomAPI_Circ2d> SketchPlugin_MacroCircle::shapeByThreePoints()
+{
+  std::string aPointAttr[3] = { FIRST_POINT_ID(),
+                                SECOND_POINT_ID(),
+                                THIRD_POINT_ID() };
+  std::string aPointRef[3] = { FIRST_POINT_REF_ID(),
+                               SECOND_POINT_REF_ID(),
+                               THIRD_POINT_REF_ID() };
+  std::shared_ptr<GeomAPI_Interface> aPassedEntities[3];
+  for (int aPntIndex = 0; aPntIndex < 3; ++aPntIndex) {
+    AttributePtr aPassedAttr = attribute(aPointAttr[aPntIndex]);
+    if (!aPassedAttr->isInitialized())
+      break;
+
+    AttributeRefAttrPtr aPassedRef = refattr(aPointRef[aPntIndex]);
+    // calculate circle parameters
+    std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
+    std::shared_ptr<GeomAPI_Shape> aTangentCurve;
+    SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
+        aPassedRef, aPassedAttr, aTangentCurve, aPassedPoint);
+
+    if (aPassedPoint)
+      aPassedEntities[aPntIndex] = aPassedPoint;
+    else
+      aPassedEntities[aPntIndex] = aTangentCurve;
   }
 
+  std::shared_ptr<GeomAPI_Ax3> anAxis = SketchPlugin_Sketch::plane(sketch());
+  std::shared_ptr<GeomAPI_Circ2d> aCircle = std::shared_ptr<GeomAPI_Circ2d>(
+      new GeomAPI_Circ2d(aPassedEntities[0], aPassedEntities[1], aPassedEntities[2], anAxis));
+  if (!aCircle->implPtr<char>())
+    return std::shared_ptr<GeomAPI_Circ2d>();
+  return aCircle;
+}
+
+std::shared_ptr<GeomAPI_Circ2d> SketchPlugin_MacroCircle::shapeByTwoPassedPoints()
+{
+  std::string aPointAttr[2] = { FIRST_POINT_ID(),
+                                SECOND_POINT_ID() };
+  std::string aPointRef[2] = { FIRST_POINT_REF_ID(),
+                               SECOND_POINT_REF_ID() };
+  std::shared_ptr<GeomAPI_Pnt2d> aPassedPoints[2]; // there is possible only two passed points
+  std::shared_ptr<GeomAPI_Interface> aPassedEntities[3];
+  int aPntIndex = 0;
+  for (; aPntIndex < 2; ++aPntIndex) {
+    AttributePtr aPassedAttr = attribute(aPointAttr[aPntIndex]);
+    if (!aPassedAttr->isInitialized())
+      break;
+
+    AttributeRefAttrPtr aPassedRef = refattr(aPointRef[aPntIndex]);
+    // calculate circle parameters
+    std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
+    std::shared_ptr<GeomAPI_Shape> aTangentCurve;
+    SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
+        aPassedRef, aPassedAttr, aTangentCurve, aPassedPoint);
+
+    if (aPassedPoint) {
+      aPassedEntities[aPntIndex] = aPassedPoint;
+      aPassedPoints[aPntIndex] = aPassedPoint;
+    } else {
+      aPassedEntities[aPntIndex] = aTangentCurve;
+      // if the circle is tangent to any curve,
+      // the third point will be initialized by the tangent point
+      aPassedEntities[2] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPassedAttr)->pnt();
+    }
+  }
+  if (aPntIndex <= 1)
+    return std::shared_ptr<GeomAPI_Circ2d>();
+
+  std::shared_ptr<GeomAPI_Circ2d> aCircle;
+  if (aPassedEntities[2]) {
+    std::shared_ptr<GeomAPI_Ax3> anAxis = SketchPlugin_Sketch::plane(sketch());
+    aCircle = std::shared_ptr<GeomAPI_Circ2d>(
+        new GeomAPI_Circ2d(aPassedEntities[0], aPassedEntities[1], aPassedEntities[2], anAxis));
+  } else {
+    // the circle is defined by two points, calculate its parameters manually
+    std::shared_ptr<GeomAPI_Pnt2d> aCenter(new GeomAPI_Pnt2d(
+        (aPassedPoints[0]->x() + aPassedPoints[1]->x()) * 0.5,
+        (aPassedPoints[0]->y() + aPassedPoints[1]->y()) * 0.5));
+    aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aPassedPoints[0]));
+  }
+  if (!aCircle->implPtr<char>())
+    return std::shared_ptr<GeomAPI_Circ2d>();
+  return aCircle;
+}
+
+AISObjectPtr SketchPlugin_MacroCircle::getAISObject(AISObjectPtr thePrevious)
+{
   SketchPlugin_Sketch* aSketch = sketch();
   if(!aSketch) {
     return AISObjectPtr();
   }
 
+  // Create circle on the sketch plane
+  std::shared_ptr<GeomAPI_Circ2d> aCircleOnSketch;
+  std::string aType = string(CIRCLE_TYPE())->value();
+  if (aType == CIRCLE_TYPE_BY_CENTER_AND_PASSED_POINTS())
+    aCircleOnSketch = shapeByCenterAndPassed();
+  else if (aType == CIRCLE_TYPE_BY_THREE_POINTS()) {
+    if (attribute(THIRD_POINT_ID())->isInitialized())
+      aCircleOnSketch = shapeByThreePoints();
+    else
+      aCircleOnSketch = shapeByTwoPassedPoints();
+  }
+
+  if (!aCircleOnSketch)
+    return AISObjectPtr();
+
+  std::shared_ptr<GeomAPI_Pnt2d> aCenter2D = aCircleOnSketch->center();
+  double aRadius = aCircleOnSketch->radius();
+
   // Compute a circle in 3D view.
-  std::shared_ptr<GeomAPI_Pnt> aCenter(aSketch->to3D(myCenter->x(), myCenter->y()));
+  std::shared_ptr<GeomAPI_Pnt> aCenter(aSketch->to3D(aCenter2D->x(), aCenter2D->y()));
   std::shared_ptr<GeomDataAPI_Dir> aNDir =
       std::dynamic_pointer_cast<GeomDataAPI_Dir>(
           aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
   std::shared_ptr<GeomAPI_Dir> aNormal = aNDir->dir();
-  GeomShapePtr aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircle(aCenter, aNormal, myRadius);
+  GeomShapePtr aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircle(aCenter, aNormal, aRadius);
   GeomShapePtr aCenterPointShape = GeomAlgoAPI_PointBuilder::vertex(aCenter);
   if(!aCircleShape.get() || !aCenterPointShape.get()) {
     return AISObjectPtr();
@@ -237,19 +298,19 @@ AISObjectPtr SketchPlugin_MacroCircle::getAISObject(AISObjectPtr thePrevious)
 }
 
 void SketchPlugin_MacroCircle::attributeChanged(const std::string& theID) {
-  // If circle type switched reset according attributes.
+  double aRadius = 0.0;
+  // If circle type switched reset all attributes.
   if(theID == CIRCLE_TYPE()) {
-    std::string aType = string(CIRCLE_TYPE())->value();
-    if(aType == CIRCLE_TYPE_BY_CENTER_AND_PASSED_POINTS()) {
-      resetAttribute(CENTER_POINT_ID());
-      resetAttribute(PASSED_POINT_ID());
-    } else if(aType == CIRCLE_TYPE_BY_THREE_POINTS()) {
-      resetAttribute(FIRST_POINT_ID());
-      resetAttribute(SECOND_POINT_ID());
-      resetAttribute(THIRD_POINT_ID());
-    }
-    myCenter.reset();
-    myRadius = 0;
+    SketchPlugin_Tools::resetAttribute(this, CENTER_POINT_ID());
+    SketchPlugin_Tools::resetAttribute(this, CENTER_POINT_REF_ID());
+    SketchPlugin_Tools::resetAttribute(this, PASSED_POINT_ID());
+    SketchPlugin_Tools::resetAttribute(this, PASSED_POINT_REF_ID());
+    SketchPlugin_Tools::resetAttribute(this, FIRST_POINT_ID());
+    SketchPlugin_Tools::resetAttribute(this, FIRST_POINT_REF_ID());
+    SketchPlugin_Tools::resetAttribute(this, SECOND_POINT_ID());
+    SketchPlugin_Tools::resetAttribute(this, SECOND_POINT_REF_ID());
+    SketchPlugin_Tools::resetAttribute(this, THIRD_POINT_ID());
+    SketchPlugin_Tools::resetAttribute(this, THIRD_POINT_REF_ID());
   } else if(theID == CENTER_POINT_ID() || theID == PASSED_POINT_ID()) {
     std::shared_ptr<GeomDataAPI_Point2D> aCenterPointAttr =
         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_POINT_ID()));
@@ -262,8 +323,7 @@ void SketchPlugin_MacroCircle::attributeChanged(const std::string& theID) {
       return;
     }
 
-    myCenter = aCenterPointAttr->pnt();
-    myRadius = myCenter->distance(aPassedPointAttr->pnt());
+    aRadius = aCenterPointAttr->pnt()->distance(aPassedPointAttr->pnt());
   } else if(theID == FIRST_POINT_ID() || theID == SECOND_POINT_ID() || theID == THIRD_POINT_ID()) {
     std::shared_ptr<GeomAPI_Pnt2d> aPoints[3];
     int aNbInitialized = 0;
@@ -274,33 +334,19 @@ void SketchPlugin_MacroCircle::attributeChanged(const std::string& theID) {
         aPoints[aNbInitialized++] = aCurPnt->pnt();
     }
 
-    if(aNbInitialized == 1) {
+    std::shared_ptr<GeomAPI_Circ2d> aCircle;
+    if(aNbInitialized == 1)
       return;
-    } else if(aNbInitialized == 2) {
-      std::shared_ptr<GeomAPI_XY> aCenterXY =
-          aPoints[0]->xy()->added(aPoints[1]->xy())->multiplied(0.5);
-      myCenter.reset(new GeomAPI_Pnt2d(aCenterXY->x(), aCenterXY->y()));
-      myRadius = aPoints[0]->distance(aPoints[1]) * 0.5;
-    } else {
-      std::shared_ptr<GeomAPI_Circ2d> aCircle(
-          new GeomAPI_Circ2d(aPoints[0], aPoints[1], aPoints[2]));
-      myCenter = aCircle->center();
-      if(myCenter.get()) {
-        myRadius = aCircle->radius();
-      }
-    }
+    else if(aNbInitialized == 2)
+      aCircle = shapeByTwoPassedPoints();
+    else
+      aCircle = shapeByThreePoints();
+    if (aCircle)
+      aRadius = aCircle->radius();
   }
 
   AttributeDoublePtr aRadiusAttr = real(CIRCLE_RADIUS_ID());
   bool aWasBlocked = data()->blockSendAttributeUpdated(true);
-  aRadiusAttr->setValue(myRadius);
+  aRadiusAttr->setValue(aRadius);
   data()->blockSendAttributeUpdated(aWasBlocked, false);
 }
-
-void SketchPlugin_MacroCircle::resetAttribute(const std::string& theId)
-{
-  AttributePtr anAttr = attribute(theId);
-  if(anAttr.get()) {
-    anAttr->reset();
-  }
-}