Salome HOME
Task 2.2. New arcs creation mode: perpendicular to a straight edge
authorazv <azv@opencascade.com>
Fri, 16 Aug 2019 05:49:58 +0000 (08:49 +0300)
committerazv <azv@opencascade.com>
Fri, 16 Aug 2019 05:49:58 +0000 (08:49 +0300)
* Implement fourth mode of arc creation: by transversal line.
* Unit test for that mode.
* Documentation update.

24 files changed:
src/GeomAlgoAPI/GeomAlgoAPI_Circ2dBuilder.cpp
src/GeomAlgoAPI/GeomAlgoAPI_Circ2dBuilder.h
src/SketchAPI/SketchAPI_MacroArc.cpp
src/SketchAPI/SketchAPI_MacroArc.h
src/SketchAPI/SketchAPI_Sketch.cpp
src/SketchAPI/SketchAPI_Sketch.h
src/SketchPlugin/CMakeLists.txt
src/SketchPlugin/SketchPlugin_MacroArc.cpp
src/SketchPlugin/SketchPlugin_MacroArc.h
src/SketchPlugin/SketchPlugin_Plugin.cpp
src/SketchPlugin/SketchPlugin_Validators.cpp
src/SketchPlugin/SketchPlugin_Validators.h
src/SketchPlugin/Test/TestCreateArcByTransversalLine.py [new file with mode: 0644]
src/SketchPlugin/doc/arcFeature.rst
src/SketchPlugin/doc/examples/arc.py
src/SketchPlugin/doc/images/Arc_panel_3pt.png
src/SketchPlugin/doc/images/Arc_panel_base.png
src/SketchPlugin/doc/images/Arc_panel_perp.png [new file with mode: 0644]
src/SketchPlugin/doc/images/Arc_panel_tang.png
src/SketchPlugin/doc/images/Arc_res.png
src/SketchPlugin/doc/images/arc_perp_32x32.png [new file with mode: 0644]
src/SketchPlugin/icons/arc_perp_32x32.png [new file with mode: 0644]
src/SketchPlugin/plugin-Sketch.xml
src/SketcherPrs/SketcherPrs_Perpendicular.cpp

index 232a0d690d894f03d646a36bc8212a881b5b2931..5b20ddb137911d80a46a9c34f108658772d063fc 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <BRep_Tool.hxx>
 #include <ElCLib.hxx>
+#include <GccAna_Circ2d2TanOn.hxx>
 #include <GccAna_Circ2d2TanRad.hxx>
 #include <GccAna_Circ2d3Tan.hxx>
 #include <GccAna_Circ2dTanCen.hxx>
@@ -48,6 +49,7 @@ typedef std::vector< std::shared_ptr<GccEnt_QualifiedLin> >  VectorOfGccLine;
 // Provide different mechanisms to create circle:
 // * by passing points
 // * by tangent edges
+// * by transversal line
 // * with specified radius
 // * etc.
 class CircleBuilder
@@ -83,6 +85,19 @@ public:
     }
   }
 
+  void setTransversalLine(const std::shared_ptr<GeomAPI_Shape>& theLine)
+  {
+    if (!theLine)
+      return;
+
+    const TopoDS_Edge& anEdge = TopoDS::Edge(theLine->impl<TopoDS_Shape>());
+
+    double aFirst, aLast;
+    TopLoc_Location aLoc;
+    Handle(Geom2d_Curve) aCurve = BRep_Tool::CurveOnSurface(anEdge, myPlane, aLoc, aFirst, aLast);
+    myTransversalLine = CurveAdaptorPtr(new Geom2dAdaptor_Curve(aCurve, aFirst, aLast));
+  }
+
   void setPassingPoints(const std::vector< std::shared_ptr<GeomAPI_Pnt2d> >& thePoints)
   {
     std::vector< std::shared_ptr<GeomAPI_Pnt2d> >::const_iterator aPIt;
@@ -115,9 +130,13 @@ public:
       case 1:
         aResult = circleByPointAndTwoTangentCurves();
         break;
-      case 2:
-        aResult = circleByTwoPointsAndTangentCurve();
+      case 2: {
+        if (myTransversalLine)
+          aResult = circleByTwoPointsAndTransversalLine();
+        else
+          aResult = circleByTwoPointsAndTangentCurve();
         break;
+      }
       case 3:
         aResult = circleByThreePassingPoints();
         break;
@@ -342,6 +361,22 @@ private:
   }
 
 
+  Circ2dPtr circleByTwoPointsAndTransversalLine()
+  {
+    const gp_Pnt2d& aPoint1 = myPassingPoints[0];
+    const gp_Pnt2d& aPoint2 = myPassingPoints[1];
+
+    if (myTransversalLine && myTransversalLine->GetType() == GeomAbs_Line) {
+      GccAna_Circ2d2TanOn aCircleBuilder(aPoint1, aPoint2, myTransversalLine->Line(),
+                                         Precision::Confusion());
+      if (aCircleBuilder.NbSolutions() > 0)
+        return Circ2dPtr(new gp_Circ2d(aCircleBuilder.ThisSolution(1)));
+    }
+
+    return Circ2dPtr();
+  }
+
+
   Circ2dPtr circleByRadiusAndTwoTangentCurves()
   {
     VectorOfGccCirc aTgCirc;
@@ -467,6 +502,7 @@ private:
   std::shared_ptr<GeomAPI_Pnt2d> myCenter;
   std::vector<gp_Pnt2d> myPassingPoints;
   std::vector<CurveAdaptorPtr> myTangentShapes;
+  CurveAdaptorPtr myTransversalLine;
   double myRadius;
   std::shared_ptr<GeomAPI_Pnt2d> myClosestPoint;
 };
@@ -497,6 +533,12 @@ void GeomAlgoAPI_Circ2dBuilder::addTangentCurve(const std::shared_ptr<GeomAPI_Sh
     myTangentShapes.push_back(theEdge);
 }
 
+void GeomAlgoAPI_Circ2dBuilder::setTransversalLine(const std::shared_ptr<GeomAPI_Shape>& theEdge)
+{
+  if (theEdge->isEdge())
+    myTransversalLine = theEdge;
+}
+
 void GeomAlgoAPI_Circ2dBuilder::addPassingPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
 {
   myPassingPoints.push_back(thePoint);
@@ -526,6 +568,7 @@ std::shared_ptr<GeomAPI_Circ2d> GeomAlgoAPI_Circ2dBuilder::circle()
   CircleBuilder aCircleBuilder(myPlane);
   aCircleBuilder.setCenter(myCenter);
   aCircleBuilder.setTangentCurves(myTangentShapes);
+  aCircleBuilder.setTransversalLine(myTransversalLine);
   aCircleBuilder.setPassingPoints(myPassingPoints);
   aCircleBuilder.setClosestPoint(myClosestPoint);
   aCircleBuilder.setRadius(myRadius);
index c193e877dc8314128d221bfc8d15b219bb021ca6..3105b504795cef29c875f33dd4b1652dec91157a 100644 (file)
@@ -58,6 +58,10 @@ public:
   GEOMALGOAPI_EXPORT
   void addTangentCurve(const std::shared_ptr<GeomAPI_Shape>& theEdge);
 
+  /// \brief Constrain circle to be orthogonal to the given edge
+  GEOMALGOAPI_EXPORT
+  void setTransversalLine(const std::shared_ptr<GeomAPI_Shape>& theEdge);
+
   /// \brief Constrain circle to pass through the given point
   GEOMALGOAPI_EXPORT
   void addPassingPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint);
@@ -82,6 +86,7 @@ private:
   std::shared_ptr<GeomAPI_Pnt2d>                myCenter;
   std::vector< std::shared_ptr<GeomAPI_Pnt2d> > myPassingPoints;
   std::vector< std::shared_ptr<GeomAPI_Shape> > myTangentShapes;
+  std::shared_ptr<GeomAPI_Shape>                myTransversalLine;
   std::shared_ptr<GeomAPI_Pnt2d>                myClosestPoint;
   double                                        myRadius;
 };
index 4bad39fefc6e56952ef3bb263bccb97807fc41a7..67dc5f0c768bcb6063d9cb07566d4cfa7aa4542e 100644 (file)
@@ -201,3 +201,29 @@ void SketchAPI_MacroArc::setByTangent(const ModelHighAPI_RefAttr& theTangentPoin
 
   execute();
 }
+
+//================================================================================================
+void SketchAPI_MacroArc::setByTransversal(const ModelHighAPI_RefAttr& theTransversalPoint,
+                                          double theEndX, double theEndY,
+                                          bool theInversed)
+{
+  fillAttribute(SketchPlugin_MacroArc::ARC_TYPE_BY_TRANSVERSAL_LINE(), myarcType);
+  fillAttribute(theTransversalPoint, mytangentPoint);
+  fillAttribute(endPoint3(), theEndX, theEndY);
+  fillAttribute(theInversed, myreversed);
+
+  execute();
+}
+
+//================================================================================================
+void SketchAPI_MacroArc::setByTransversal(const ModelHighAPI_RefAttr& theTransversalPoint,
+                                          const std::shared_ptr<GeomAPI_Pnt2d>& theEnd,
+                                          bool theInversed)
+{
+  fillAttribute(SketchPlugin_MacroArc::ARC_TYPE_BY_TRANSVERSAL_LINE(), myarcType);
+  fillAttribute(theTransversalPoint, mytangentPoint);
+  fillAttribute(theEnd, myendPoint3);
+  fillAttribute(theInversed, myreversed);
+
+  execute();
+}
index a4b51ccec3371c608df32034166edab32e63b50c..3a6ae556604c73c01c28ae6110ae009519603f15 100644 (file)
@@ -114,8 +114,6 @@ public:
                angle, SketchPlugin_MacroArc::ANGLE_ID(),
                ModelAPI_AttributeDouble, /** Angle */)
 
-private:
-
   /// Set by center and start, end point.
   SKETCHAPI_EXPORT
   void setByCenterStartEnd(double theCenterX, double theCenterY,
@@ -153,6 +151,18 @@ private:
   void setByTangent(const ModelHighAPI_RefAttr& theTangentPoint,
                     const std::shared_ptr<GeomAPI_Pnt2d>& theEnd,
                     bool theInversed);
+
+  /// Set by tangent and end point.
+  SKETCHAPI_EXPORT
+  void setByTransversal(const ModelHighAPI_RefAttr& theTransversalPoint,
+                        double theEndX, double theEndY,
+                        bool theInversed);
+
+  /// Set by tangent and end point.
+  SKETCHAPI_EXPORT
+  void setByTransversal(const ModelHighAPI_RefAttr& theTransversalPoint,
+                        const std::shared_ptr<GeomAPI_Pnt2d>& theEnd,
+                        bool theInversed);
 };
 
 /// Pointer on Arc object.
index 66e043c1c85b201f3ebc64051c866b825a7a0263..b4b43cbb389a565e6bd866455bdef2cd5bb71630 100644 (file)
@@ -460,22 +460,33 @@ std::shared_ptr<SketchAPI_MacroArc> SketchAPI_Sketch::addArc(
 std::shared_ptr<SketchAPI_MacroArc> SketchAPI_Sketch::addArc(
                                                 const ModelHighAPI_RefAttr& theTangentPoint,
                                                 double theEndX, double theEndY,
-                                                bool theInversed)
+                                                bool theInversed,
+                                                bool theTransversal)
 {
   std::shared_ptr<ModelAPI_Feature> aFeature =
     compositeFeature()->addFeature(SketchPlugin_MacroArc::ID());
-  return MacroArcPtr(new SketchAPI_MacroArc(
-    aFeature, theTangentPoint, theEndX, theEndY, theInversed));
+  MacroArcPtr aMacroArc(new SketchAPI_MacroArc(aFeature));
+  if (theTransversal)
+    aMacroArc->setByTransversal(theTangentPoint, theEndX, theEndY, theInversed);
+  else
+    aMacroArc->setByTangent(theTangentPoint, theEndX, theEndY, theInversed);
+  return aMacroArc;
 }
 
 std::shared_ptr<SketchAPI_MacroArc> SketchAPI_Sketch::addArc(
                                               const ModelHighAPI_RefAttr& theTangentPoint,
                                               const std::shared_ptr<GeomAPI_Pnt2d>& theEnd,
-                                              bool theInversed)
+                                              bool theInversed,
+                                              bool theTransversal)
 {
   std::shared_ptr<ModelAPI_Feature> aFeature =
     compositeFeature()->addFeature(SketchPlugin_MacroArc::ID());
-  return MacroArcPtr(new SketchAPI_MacroArc(aFeature, theTangentPoint, theEnd, theInversed));
+  MacroArcPtr aMacroArc(new SketchAPI_MacroArc(aFeature));
+  if (theTransversal)
+    aMacroArc->setByTransversal(theTangentPoint, theEnd, theInversed);
+  else
+    aMacroArc->setByTangent(theTangentPoint, theEnd, theInversed);
+  return aMacroArc;
 }
 
 std::shared_ptr<SketchAPI_Arc> SketchAPI_Sketch::addArc(const ModelHighAPI_Selection & theExternal)
index 8b3237f7f04df08e3cb8e3da1dbf4a4e49185f90..27a5c543d8ebe21b780bbe1b1932f464f6aa87f3 100644 (file)
@@ -236,19 +236,21 @@ public:
       const std::shared_ptr<GeomAPI_Pnt2d>& theEnd,
       const std::shared_ptr<GeomAPI_Pnt2d>& thePassed);
 
-  /// Add arc
+  /// Add transversal/tangent arc
   SKETCHAPI_EXPORT
   std::shared_ptr<SketchAPI_MacroArc> addArc(
-      const ModelHighAPI_RefAttr& theTangentPoint,
+      const ModelHighAPI_RefAttr& theConnectedPoint,
       double theEndX, double theEndY,
-      bool theInversed);
+      bool theInversed,
+      bool theTransversal = false);
 
-  /// Add arc
+  /// Add transversal/tangent arc
   SKETCHAPI_EXPORT
   std::shared_ptr<SketchAPI_MacroArc> addArc(
-      const ModelHighAPI_RefAttr& theTangentPoint,
+      const ModelHighAPI_RefAttr& theConnectedPoint,
       const std::shared_ptr<GeomAPI_Pnt2d>& theEnd,
-      bool theInversed);
+      bool theInversed,
+      bool theTransversal = false);
 
   /// Add arc
   SKETCHAPI_EXPORT
index f11be779923255237987b572ec4455c33f0280b6..cd9bc43fb6480b23783e8f493cce1ec0540db8b9 100644 (file)
@@ -222,6 +222,7 @@ ADD_UNIT_TESTS(
   TestCreateArcByCenterStartEnd.py
   TestCreateArcByTangentEdge.py
   TestCreateArcByThreePoints.py
+  TestCreateArcByTransversalLine.py
   TestCreateArcChangeType.py
   TestCreateCircleByCenterAndPassed.py
   TestCreateCircleByThreePoints.py
index 3e6327e08ef04fc5a9bc844f1018048a0014266d..f0379c4618eac92385f15b151b3f1eaedd048e20 100644 (file)
@@ -20,6 +20,7 @@
 #include "SketchPlugin_MacroArc.h"
 
 #include "SketchPlugin_Arc.h"
+#include "SketchPlugin_ConstraintPerpendicular.h"
 #include "SketchPlugin_ConstraintTangent.h"
 #include "SketchPlugin_Sketch.h"
 #include "SketchPlugin_Tools.h"
@@ -209,7 +210,9 @@ void SketchPlugin_MacroArc::attributeChanged(const std::string& theID)
   else if(anArcType == ARC_TYPE_BY_THREE_POINTS())
     fillByThreePassedPoints();
   else if(anArcType == ARC_TYPE_BY_TANGENT_EDGE())
-    fillByTangentEdge();
+    fillByEdge(false);
+  else if (anArcType == ARC_TYPE_BY_TRANSVERSAL_LINE())
+    fillByEdge(true);
 
   double aRadius = 0;
   double anAngle = 0;
@@ -339,19 +342,27 @@ void SketchPlugin_MacroArc::execute()
                                          AttributePtr(),
                                          anArcFeature->lastResult(),
                                          true);
-  } else if(anArcType == ARC_TYPE_BY_TANGENT_EDGE()) {
-    // constraints for tangent arc
+  } else {
+    // coincident with connection point
     SketchPlugin_Tools::createCoincidenceOrTangency(this,
                                          TANGENT_POINT_ID(),
                                          anArcFeature->attribute(SketchPlugin_Arc::START_ID()),
                                          ObjectPtr(),
                                          false);
-    FeaturePtr aTangent = sketch()->addFeature(SketchPlugin_ConstraintTangent::ID());
-    AttributeRefAttrPtr aRefAttrA = aTangent->refattr(SketchPlugin_Constraint::ENTITY_A());
+    // tangent or perpendicular constraint
+    FeaturePtr aStartPointConstraint;
+    if (anArcType == ARC_TYPE_BY_TANGENT_EDGE())
+      aStartPointConstraint = sketch()->addFeature(SketchPlugin_ConstraintTangent::ID());
+    else
+      aStartPointConstraint = sketch()->addFeature(SketchPlugin_ConstraintPerpendicular::ID());
+    // setting attributes of the start point constraint
+    AttributeRefAttrPtr aRefAttrA =
+        aStartPointConstraint->refattr(SketchPlugin_Constraint::ENTITY_A());
     AttributeRefAttrPtr aTgPntRefAttr = refattr(TANGENT_POINT_ID());
     FeaturePtr aTgFeature = ModelAPI_Feature::feature(aTgPntRefAttr->attr()->owner());
     aRefAttrA->setObject(aTgFeature->lastResult());
-    AttributeRefAttrPtr aRefAttrB = aTangent->refattr(SketchPlugin_Constraint::ENTITY_B());
+    AttributeRefAttrPtr aRefAttrB =
+        aStartPointConstraint->refattr(SketchPlugin_Constraint::ENTITY_B());
     aRefAttrB->setObject(anArcFeature->lastResult());
     // constraint for end point
     SketchPlugin_Tools::createCoincidenceOrTangency(this,
@@ -596,15 +607,15 @@ void SketchPlugin_MacroArc::recalculateReversedFlagByPassed(
   myParamBefore = aEndParam;
 }
 
-void SketchPlugin_MacroArc::fillByTangentEdge()
+void SketchPlugin_MacroArc::fillByEdge(bool theTransversal)
 {
   AttributeRefAttrPtr aTangentAttr = refattr(TANGENT_POINT_ID());
   if (!aTangentAttr->isInitialized())
     return;
 
-  AttributePoint2DPtr aTangentPointAttr =
+  AttributePoint2DPtr aConnectionPointAttr =
       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aTangentAttr->attr());
-  if (!aTangentPointAttr->isInitialized())
+  if (!aConnectionPointAttr->isInitialized())
     return;
 
   AttributePoint2DPtr anEndPointAttr =
@@ -612,19 +623,22 @@ void SketchPlugin_MacroArc::fillByTangentEdge()
   if (!anEndPointAttr->isInitialized())
     return;
 
-  myStart = aTangentPointAttr->pnt();
+  myStart = aConnectionPointAttr->pnt();
   myEnd = anEndPointAttr->pnt();
   if (myStart->isEqual(myEnd))
     return;
 
   // obtain a shape the tangent point belongs to
-  FeaturePtr aTangentFeature = ModelAPI_Feature::feature(aTangentPointAttr->owner());
-  std::shared_ptr<GeomAPI_Shape> aTangentShape = aTangentFeature->lastResult()->shape();
+  FeaturePtr aConnectedFeature = ModelAPI_Feature::feature(aConnectionPointAttr->owner());
+  std::shared_ptr<GeomAPI_Shape> aTangentShape = aConnectedFeature->lastResult()->shape();
 
   GeomAlgoAPI_Circ2dBuilder aCircBuilder(SketchPlugin_Sketch::plane(sketch()));
   aCircBuilder.addPassingPoint(myStart);
   aCircBuilder.addPassingPoint(myEnd);
-  aCircBuilder.addTangentCurve(aTangentShape);
+  if (theTransversal)
+    aCircBuilder.setTransversalLine(aTangentShape);
+  else
+    aCircBuilder.addTangentCurve(aTangentShape);
 
   std::shared_ptr<GeomAPI_Circ2d> aCircle = aCircBuilder.circle();
   if (!aCircle)
index 815cd7002fce88c7d4f6f47a28a48734396b6983..886f6efdcb91b8de25eb0e88f30d254c6ddf47c5 100644 (file)
@@ -72,6 +72,12 @@ class SketchPlugin_MacroArc: public SketchPlugin_SketchEntity,
     return ID;
   }
 
+  inline static const std::string& ARC_TYPE_BY_TRANSVERSAL_LINE()
+  {
+    static const std::string ID("by_transversal_line");
+    return ID;
+  }
+
   /// Central 2D point of the circle which contains the arc
   inline static const std::string& CENTER_POINT_ID()
   {
@@ -220,8 +226,9 @@ private:
   void fillByCenterAndTwoPassed();
   /// Set fields for center, start and end points by selected passed points
   void fillByThreePassedPoints();
-  /// Set fields for center, start and end points by selected tangent edge
-  void fillByTangentEdge();
+  /// Set fields for center, start and end points by selected tangent or transversal edge
+  /// \param theTransversal if \c true, builds transversal arc, otherwise builds tangential arc.
+  void fillByEdge(bool theTransversal);
 
   FeaturePtr createArcFeature();
 
index 5d1e9804e9762d14ebe1f6be6bc1fc91b69e0e11..67d4e4656695938703899b92bf24ecd2ef18f0ae 100644 (file)
@@ -119,6 +119,8 @@ SketchPlugin_Plugin::SketchPlugin_Plugin()
                               new SketchPlugin_MiddlePointAttrValidator);
   aFactory->registerValidator("SketchPlugin_ArcTangentPoint",
                               new SketchPlugin_ArcTangentPointValidator);
+  aFactory->registerValidator("SketchPlugin_ArcTransversalPoint",
+                              new SketchPlugin_ArcTransversalPointValidator);
   aFactory->registerValidator("SketchPlugin_IntersectionValidator",
                               new SketchPlugin_IntersectionValidator);
   aFactory->registerValidator("SketchPlugin_ProjectionValidator",
index e95372a35d82cd36ad943d4b37d6432bb0d3c3a9..a0cbf6805babe131cb0468d78aedc8da5e308e11 100644 (file)
@@ -836,6 +836,44 @@ bool SketchPlugin_ArcTangentPointValidator::isValid(const AttributePtr& theAttri
   return true;
 }
 
+bool SketchPlugin_ArcTransversalPointValidator::isValid(
+    const AttributePtr& theAttribute,
+    const std::list<std::string>& /*theArguments*/,
+    Events_InfoMessage& theError) const
+{
+  if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
+    theError = "The attribute with the %1 type is not processed";
+    theError.arg(theAttribute->attributeType());
+    return false;
+  }
+  AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
+  AttributePtr anAttr = aRefAttr->attr();
+  if (!anAttr) {
+    theError = "The attribute %1 should be a point";
+    theError.arg(theAttribute->id());
+    return false;
+  }
+
+  FeaturePtr anAttrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anAttr->owner());
+  const std::string& aFeatureType = anAttrFeature->getKind();
+  if (aFeatureType == SketchPlugin_Line::ID()) {
+    // selected point should be bound point of line
+    const std::string& aPntId = anAttr->id();
+    if (aPntId != SketchPlugin_Line::START_ID() && aPntId != SketchPlugin_Line::END_ID()) {
+      theError = "The attribute %1 is not supported";
+      theError.arg(aPntId);
+      return false;
+    }
+  }
+  else {
+    theError = "Unable to build transversal arc on %1";
+    theError.arg(anAttrFeature->getKind());
+    return false;
+  }
+
+  return true;
+}
+
 bool SketchPlugin_IntersectionValidator::isValid(const AttributePtr& theAttribute,
                                                  const std::list<std::string>& theArguments,
                                                  Events_InfoMessage& theError) const
index d988ac751209adc80915b5015a27c7d4c3441d76..b3fe8f57464ee41781dcfe9d114f9caaac735a89 100644 (file)
@@ -249,6 +249,25 @@ class SketchPlugin_ArcTangentPointValidator : public ModelAPI_AttributeValidator
                        Events_InfoMessage& theError) const;
 };
 
+/**\class SketchPlugin_ArcTransversalPointValidator
+ * \ingroup Validators
+ * \brief Validator for the point where the transversal arc is building.
+ *
+ * Checks that the point is a start or end point just on line or arc.
+ */
+class SketchPlugin_ArcTransversalPointValidator : public ModelAPI_AttributeValidator
+{
+ public:
+  //! returns true if attribute is valid
+  //! \param theAttribute the checked attribute
+  //! \param theArguments arguments of the attribute
+  //! \param theError error message
+  virtual bool isValid(const AttributePtr& theAttribute,
+                       const std::list<std::string>& theArguments,
+                       Events_InfoMessage& theError) const;
+};
+
+
 /**\class SketchPlugin_SplitValidator
  * \ingroup Validators
  * \brief Validator for the entity of the following type:
diff --git a/src/SketchPlugin/Test/TestCreateArcByTransversalLine.py b/src/SketchPlugin/Test/TestCreateArcByTransversalLine.py
new file mode 100644 (file)
index 0000000..0250f95
--- /dev/null
@@ -0,0 +1,163 @@
+# Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+
+#=========================================================================
+# Initialization of the test
+#=========================================================================
+from GeomDataAPI import *
+from ModelAPI import *
+from SketchAPI import SketchAPI_Sketch
+import math
+from salome.shaper import model
+
+__updated__ = "2019-08-16"
+
+TOLERANCE = 1.e-7
+
+#=========================================================================
+# Auxiliary functions
+#=========================================================================
+
+def verifyLastArc(theSketch, theCenter, theStart, theEnd):
+    """
+    subroutine to verify position of last arc in the sketch
+    """
+    aLastArc = model.lastSubFeature(theSketch, "SketchArc")
+    model.assertArc(aLastArc, theCenter, theStart, theEnd)
+
+def verifyArcLineTransversal(theArc, theLine):
+    aCenter = geomDataAPI_Point2D(theArc.attribute("center_point"))
+    aDistCL = model.distancePointLine(aCenter, theLine)
+    assert aDistCL < TOLERANCE, "Arc and line are not orthogonal"
+
+def verifyPointOnArc(thePoint, theArc):
+    aCenter = geomDataAPI_Point2D(theArc.attribute("center_point"))
+    aStart = geomDataAPI_Point2D(theArc.attribute("start_point"))
+    aRadius = model.distancePointPoint(aStart, aCenter)
+
+    aDistPP = model.distancePointPoint(aCenter, thePoint)
+    assert math.fabs(aRadius - aDistPP) < TOLERANCE, "Point is not on Circle, distance: {0}".format(aDistPP)
+
+
+
+aSession = ModelAPI_Session.get()
+aDocument = aSession.moduleDocument()
+#=========================================================================
+# Creation of a sketch
+#=========================================================================
+aSession.startOperation()
+aSketchCommonFeature = aDocument.addFeature("Sketch")
+aSketchFeature = featureToCompositeFeature(aSketchCommonFeature)
+origin = geomDataAPI_Point(aSketchFeature.attribute("Origin"))
+origin.setValue(0, 0, 0)
+dirx = geomDataAPI_Dir(aSketchFeature.attribute("DirX"))
+dirx.setValue(1, 0, 0)
+norm = geomDataAPI_Dir(aSketchFeature.attribute("Norm"))
+norm.setValue(0, 0, 1)
+aSession.finishOperation()
+aSketch = SketchAPI_Sketch(aSketchFeature)
+
+# auxiliary line
+aLineStartPnt = [0., 0.]
+aLineEndPnt = [50., 0.]
+aSession.startOperation()
+aSketchLine = aSketchFeature.addFeature("SketchLine")
+aLineStart = geomDataAPI_Point2D(aSketchLine.attribute("StartPoint"))
+aLineEnd = geomDataAPI_Point2D(aSketchLine.attribute("EndPoint"))
+aLineStart.setValue(aLineStartPnt[0], aLineStartPnt[1])
+aLineEnd.setValue(aLineEndPnt[0], aLineEndPnt[1])
+aSession.finishOperation()
+
+#=========================================================================
+# Test 1. Create an arc, orthogonal to the line
+#=========================================================================
+anArcEndPnt = [80., 20.]
+aSession.startOperation()
+anArc = aSketchFeature.addFeature("SketchMacroArc")
+assert (anArc.getKind() == "SketchMacroArc")
+anArcTgPnt = anArc.refattr("tangent_point")
+assert (not anArcTgPnt.isInitialized())
+anArcEnd = geomDataAPI_Point2D(anArc.attribute("end_point_3"))
+assert (not anArcEnd.isInitialized())
+anArcType = anArc.string("arc_type")
+assert (not anArcType.isInitialized())
+# initialize attributes
+anArcType.setValue("by_transversal_line")
+anArcTgPnt.setAttr(aLineEnd)
+anArcEnd.setValue(anArcEndPnt[0], anArcEndPnt[1])
+aSession.finishOperation()
+verifyLastArc(aSketchFeature, [], aLineEndPnt, anArcEndPnt)
+aLastArc = model.lastSubFeature(aSketchFeature, "SketchArc")
+verifyArcLineTransversal(aLastArc, aSketchLine)
+model.testNbSubFeatures(aSketch, "SketchConstraintCoincidence", 1)
+model.testNbSubFeatures(aSketch, "SketchConstraintPerpendicular", 1)
+
+#=========================================================================
+# Test 2. Create an arc, orthogonal to the previous arc (expect an error)
+#=========================================================================
+aPrevArc = aLastArc
+aPrevArcEnd = geomDataAPI_Point2D(aPrevArc.attribute("end_point"))
+anArcEndPnt = [50., 100.]
+aSession.startOperation()
+anArc = aSketchFeature.addFeature("SketchMacroArc")
+anArcTgPnt = anArc.refattr("tangent_point")
+anArcEnd = geomDataAPI_Point2D(anArc.attribute("end_point_3"))
+anArcType = anArc.string("arc_type")
+# initialize attributes
+anArcType.setValue("by_transversal_line")
+anArcTgPnt.setAttr(aPrevArcEnd)
+anArcEnd.setValue(anArcEndPnt[0], anArcEndPnt[1])
+aSession.finishOperation()
+assert(anArc.error() != "")
+# remove failed feature
+aSession.startOperation()
+aDocument.removeFeature(anArc)
+aSession.finishOperation()
+
+#=========================================================================
+# Test 3. Create an arc, orthogonal to the line with end point on the arc
+#=========================================================================
+aPrevArc = model.lastSubFeature(aSketchFeature, "SketchArc")
+aPrevArcEnd = geomDataAPI_Point2D(aPrevArc.attribute("end_point"))
+aSession.startOperation()
+anArc = aSketchFeature.addFeature("SketchMacroArc")
+anArcTgPnt = anArc.refattr("tangent_point")
+anArcEnd = geomDataAPI_Point2D(anArc.attribute("end_point_3"))
+anArcEndRef = anArc.refattr("end_point_ref")
+anArcType = anArc.string("arc_type")
+# initialize attributes
+anArcType.setValue("by_transversal_line")
+anArcTgPnt.setAttr(aLineStart)
+anArcEndRef.setObject(aPrevArc.lastResult())
+anArcEnd.setValue(anArcEndPnt[0], anArcEndPnt[1])
+aSession.finishOperation()
+verifyLastArc(aSketchFeature, [], [aLineStart.x(), aLineStart.y()], [])
+aLastArc = model.lastSubFeature(aSketchFeature, "SketchArc")
+verifyArcLineTransversal(aLastArc, aSketchLine)
+aLastArcEnd = geomDataAPI_Point2D(aLastArc.attribute("end_point"))
+verifyPointOnArc(aLastArcEnd, aPrevArc)
+model.testNbSubFeatures(aSketch, "SketchConstraintCoincidence", 3)
+model.testNbSubFeatures(aSketch, "SketchConstraintPerpendicular", 2)
+
+#=========================================================================
+# End of test
+#=========================================================================
+
+assert(model.checkPythonDump())
index 9139ea4db9c7980ba2520635ec00bf43862c4150..b00034cbe5cea3ba6354702427aad3ed87b31f74 100644 (file)
@@ -10,7 +10,7 @@ To add a new Arc to the Sketch:
 #. select in the Main Menu *Sketch - > Arc* item  or
 #. click |arc.icon| **Arc** button in Sketch toolbar:
 
-There are 3 algorithms for creation of an Arc:
+There are 4 algorithms for creation of an Arc:
 
 .. image:: images/arc_base_32x32.png
    :align: left
@@ -24,6 +24,10 @@ There are 3 algorithms for creation of an Arc:
    :align: left
 **By tangent point and end point** creates an arc segment with the tangent point and the end point.
 
+.. image:: images/arc_perp_32x32.png
+   :align: left
+**By transversal point and end point** creates an arc segment perpendicular to a straight line with the start point, connected with boundary of this line, and the end point.
+
 By center and two points
 """"""""""""""""""""""""
 
@@ -90,12 +94,36 @@ The tangent point by itself is a start point. The edge on which it lies will be
 
 **TUI Command**:
 
-.. py:function:: Sketch_1.addArc(TangetPoint, EndX, EndY, Inversed)
+.. py:function:: Sketch_1.addArc(TangentPoint, EndX, EndY, Inversed)
+
+    :param object: Tangent Point.
+    :param real: End X.
+    :param real: End Y.
+    :param boolean: Is inversed.
+    :return: Result object.
+
+By transveral point and point
+"""""""""""""""""""""""""""""
+
+.. image:: images/Arc_panel_perp.png
+   :align: center
+
+Select a point on a straight segment in the view to set the transversal point, then move the mouse and click to set the end point.
+The transversal point by itself is a start point. The edge on which it lies will be perpendicular to the arc (the center of the arc is lying on the edge).
+
+- When entering a transversal point by selecting a point on segment, a Perpendicular constraint is created.
+- When entering an end point by selecting a segment, a Coincident constraint is created.
+- When entering an end point, only segments are selectable.
+
+**TUI Command**:
+
+.. py:function:: Sketch_1.addArc(TransversalPoint, EndX, EndY, Inversed, True)
 
-    :param object: Tanget Point.
+    :param object: Transversal Point.
     :param real: End X.
     :param real: End Y.
     :param boolean: Is inversed.
+    :param boolean: Arc is transversal (always True).
     :return: Result object.
 
 Result
index 3d44a951d86c41603bfaa186aa6298bc53d2abb7..cad2078bf9d72f7190a411dafd2f25a817b0ffc7 100644 (file)
@@ -10,5 +10,6 @@ SketchArc_2 = Sketch_1.addArc(8.1, 56.7, 58.2, 6.6, 44.8, 69.2)
 SketchLine_3 = Sketch_1.addLine(25.0, 109.4, 68.1, 153.6)
 SketchLine_3.setAuxiliary(True)
 SketchArc_3 = Sketch_1.addArc(SketchLine_3.startPoint(), 92.1, 34.0, True)
+SketchArc_4 = Sketch_1.addArc(SketchLine_3.endPoint(), 150.0, 10.0, True, True)
 model.do()
 model.end()
index 089d50730b22e133d05303bec7a93f95039ff42e..fd1b9aa8222b272545ae6b5234fda67fe2cffc7d 100644 (file)
Binary files a/src/SketchPlugin/doc/images/Arc_panel_3pt.png and b/src/SketchPlugin/doc/images/Arc_panel_3pt.png differ
index 9a5b9ed4a95cb5807180d49b6668a17cf2a36b7b..f702ca8bed48e2fd0eba6e80765590ff7ef3af5a 100644 (file)
Binary files a/src/SketchPlugin/doc/images/Arc_panel_base.png and b/src/SketchPlugin/doc/images/Arc_panel_base.png differ
diff --git a/src/SketchPlugin/doc/images/Arc_panel_perp.png b/src/SketchPlugin/doc/images/Arc_panel_perp.png
new file mode 100644 (file)
index 0000000..3e33cf9
Binary files /dev/null and b/src/SketchPlugin/doc/images/Arc_panel_perp.png differ
index ca02054011cb4b73ec2d6e950eda6e196622d55f..a14b891acaecd71f2a634254fdb70364cd604b42 100644 (file)
Binary files a/src/SketchPlugin/doc/images/Arc_panel_tang.png and b/src/SketchPlugin/doc/images/Arc_panel_tang.png differ
index b23a9022b44b0b5515292be17d51c26b7e8f31e4..1772eda3593471d5ad235c2c5cd31c86b6feae13 100644 (file)
Binary files a/src/SketchPlugin/doc/images/Arc_res.png and b/src/SketchPlugin/doc/images/Arc_res.png differ
diff --git a/src/SketchPlugin/doc/images/arc_perp_32x32.png b/src/SketchPlugin/doc/images/arc_perp_32x32.png
new file mode 100644 (file)
index 0000000..56f9f83
Binary files /dev/null and b/src/SketchPlugin/doc/images/arc_perp_32x32.png differ
diff --git a/src/SketchPlugin/icons/arc_perp_32x32.png b/src/SketchPlugin/icons/arc_perp_32x32.png
new file mode 100644 (file)
index 0000000..56f9f83
Binary files /dev/null and b/src/SketchPlugin/icons/arc_perp_32x32.png differ
index e3b5511c9e6486a39e2017aba9cf4863e32744a1..76871ab1beb1b9bbcb9d40a479f53cfb6fed1850 100644 (file)
               <validator id="SketchPlugin_ArcEndPointValidator" parameters="end_point_ref"/>
             </sketch-2dpoint_selector>
           </box>
+          <box id="by_transversal_line"
+               icon="icons/Sketch/arc_perp_32x32.png"
+               title="Perpendicular to line">
+            <sketch_shape_selector id="tangent_point"
+                                   label="Transversal point"
+                                   tooltip="Select point on line"
+                                   shape_types="vertex">
+              <validator id="SketchPlugin_ArcTransversalPoint"/>
+            </sketch_shape_selector>
+            <sketch-2dpoint_selector id="end_point_3"
+                                     reference_attribute="end_point_ref"
+                                     title="End point"
+                                     tooltip="End point"
+                                     accept_expressions="0"
+                                     enable_value="enable_by_preferences">
+              <validator id="SketchPlugin_ArcEndPointValidator" parameters="end_point_ref"/>
+            </sketch-2dpoint_selector>
+          </box>
         </toolbox>
         <labelvalue id="radius"
                     icon="icons/Sketch/radius.png"
index 6ef12df79b9871c76aa6a066ba1a4abd58a22ac5..acd166cb9343a2fa375c219f22e53c6f9605e4c8 100644 (file)
@@ -94,14 +94,13 @@ bool SketcherPrs_Perpendicular::updateIfReadyToDisplay(double theStep, bool with
 void SketcherPrs_Perpendicular::drawLines(const Handle(Prs3d_Presentation)& thePrs,
                                           Quantity_Color theColor) const
 {
-  Handle(Graphic3d_Group) aGroup = Prs3d_Root::CurrentGroup(thePrs);
-
-  Handle(Graphic3d_AspectLine3d) aLineAspect =
-    new Graphic3d_AspectLine3d(theColor, Aspect_TOL_SOLID, 2);
-  aGroup->SetPrimitivesAspect(aLineAspect);
-
   // Draw constrained lines
-  addLine(aGroup, SketchPlugin_Constraint::ENTITY_A());
-  addLine(aGroup, SketchPlugin_Constraint::ENTITY_B());
+  for (int i = 0; i < 2; ++i) {
+    ObjectPtr anObj =
+        SketcherPrs_Tools::getResult(myConstraint, SketchPlugin_Constraint::ATTRIBUTE(i));
+    GeomShapePtr aShape = SketcherPrs_Tools::getShape(anObj);
+    if (!aShape)
+      return;
+    drawShape(aShape, thePrs, theColor);
+  }
 }
-