Salome HOME
Task 2.12. New entities: ellipses and arcs of ellipses (issue #3003)
authorazv <azv@opencascade.com>
Tue, 24 Sep 2019 11:37:55 +0000 (14:37 +0300)
committerazv <azv@opencascade.com>
Tue, 24 Sep 2019 11:39:09 +0000 (14:39 +0300)
Implementation of elliptical arc and processing its modification in 3D viewer.

25 files changed:
src/GeomAPI/GeomAPI_Ellipse.cpp
src/GeomAPI/GeomAPI_Ellipse.h
src/GeomAPI/GeomAPI_Ellipse2d.cpp
src/GeomAPI/GeomAPI_Ellipse2d.h
src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.cpp
src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.h
src/SketchPlugin/CMakeLists.txt
src/SketchPlugin/SketchPlugin_EllipticArc.cpp [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_EllipticArc.h [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_MacroEllipse.cpp
src/SketchPlugin/SketchPlugin_MacroEllipse.h
src/SketchPlugin/SketchPlugin_MacroEllipticArc.cpp [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_MacroEllipticArc.h [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_Plugin.cpp
src/SketchPlugin/SketchPlugin_Tools.cpp
src/SketchPlugin/SketchPlugin_Tools.h
src/SketchPlugin/SketchPlugin_Validators.cpp
src/SketchPlugin/plugin-Sketch.xml
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EdgeWrapper.cpp
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_FeatureBuilder.cpp
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.h
src/SketchSolver/SketchSolver_ConstraintFixed.cpp
src/SketchSolver/SketchSolver_ConstraintMovement.cpp

index 243be630e507b5ae4ff99c22285dd24a06983e79..86a0391cb87990d1406ba34be886cb46b8666644 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <Geom_Ellipse.hxx>
 #include <GeomAPI_ProjectPointOnCurve.hxx>
+#include <GeomLib_Tool.hxx>
 #include <gp_Elips.hxx>
 
 #define MY_ELIPS implPtr<gp_Elips>()
@@ -101,3 +102,12 @@ const std::shared_ptr<GeomAPI_Pnt> GeomAPI_Ellipse::project(
   }
   return aResult;
 }
+
+const bool GeomAPI_Ellipse::parameter(const std::shared_ptr<GeomAPI_Pnt> thePoint,
+                                      const double theTolerance,
+                                      double& theParameter) const
+{
+  Handle(Geom_Ellipse) aCurve = new Geom_Ellipse(*MY_ELIPS);
+  return GeomLib_Tool::Parameter(aCurve, thePoint->impl<gp_Pnt>(),
+                                 theTolerance, theParameter) == Standard_True;
+}
index dc41993a05e472d0e160352659c8797c50dec465..9f1be781af3dea9784c609ebe2acef484e164b5e 100644 (file)
@@ -77,6 +77,19 @@ public:
   /// Project point on ellipse
   GEOMAPI_EXPORT const std::shared_ptr<GeomAPI_Pnt> project(
       const std::shared_ptr<GeomAPI_Pnt>& thePoint) const;
+
+  /** \brief Computes the parameter of a given point on an ellipse. The point must be
+   *         located either on the circle itself or relatively to the latter
+   *         at a distance less than the tolerance value. Return FALSE if the point
+   *         is beyond the tolerance limit or if computation fails.
+   *         Max Tolerance value is currently limited to 1.e-4
+   *  \param[in]  thePoint point of origin.
+   *  \param[in]  theTolerance tolerance of computation.
+   *  \param[out] theParameter resulting parameter.
+   */
+  GEOMAPI_EXPORT const bool parameter(const std::shared_ptr<GeomAPI_Pnt> thePoint,
+                                      const double theTolerance,
+                                      double& theParameter) const;
 };
 
 //! Pointer on the object
index 4a4c9950dbcd2e3f39094e24c7f9df39b222e0a3..7db3ef8a4461f0329cc9004e8ee002d34331efce 100644 (file)
@@ -31,6 +31,8 @@
 #include <Extrema_ExtElC2d.hxx>
 #include <Geom2d_Ellipse.hxx>
 #include <Geom2dAdaptor_Curve.hxx>
+#include <Geom2dAPI_ProjectPointOnCurve.hxx>
+#include <GeomLib_Tool.hxx>
 #include <gp_Ax22d.hxx>
 #include <gp_Elips2d.hxx>
 #include <Precision.hxx>
@@ -169,3 +171,32 @@ double GeomAPI_Ellipse2d::distance(const std::shared_ptr<GeomAPI_Ellipse2d>& the
   delete anExtema;
   return aDistance;
 }
+
+const std::shared_ptr<GeomAPI_Pnt2d> GeomAPI_Ellipse2d::project(
+    const std::shared_ptr<GeomAPI_Pnt2d>& thePoint) const
+{
+  std::shared_ptr<GeomAPI_Pnt2d> aResult;
+  if (!MY_ELLIPSE)
+    return aResult;
+
+  Handle(Geom2d_Ellipse) aEllipse = new Geom2d_Ellipse(*MY_ELLIPSE);
+
+  const gp_Pnt2d& aPoint = thePoint->impl<gp_Pnt2d>();
+
+  Geom2dAPI_ProjectPointOnCurve aProj(aPoint, aEllipse);
+  Standard_Integer aNbPoint = aProj.NbPoints();
+  if (aNbPoint > 0) {
+    gp_Pnt2d aNearest = aProj.NearestPoint();
+    aResult.reset(new GeomAPI_Pnt2d(aNearest.X(), aNearest.Y()));
+  }
+  return aResult;
+}
+
+const bool GeomAPI_Ellipse2d::parameter(const std::shared_ptr<GeomAPI_Pnt2d> thePoint,
+                                        const double theTolerance,
+                                        double& theParameter) const
+{
+  Handle(Geom2d_Ellipse) aCurve = new Geom2d_Ellipse(*MY_ELLIPSE);
+  return GeomLib_Tool::Parameter(aCurve, thePoint->impl<gp_Pnt2d>(),
+                                 theTolerance, theParameter) == Standard_True;
+}
index bda3221e12b70840ae6d50fe71ef6259333d5919..7772abbf15b2b396ef864b0c655626969f265a92 100644 (file)
@@ -66,6 +66,23 @@ public:
   /// Returns major radius of the ellipse
   GEOMAPI_EXPORT double majorRadius() const;
 
+  /// Project point on ellipse
+  GEOMAPI_EXPORT const std::shared_ptr<GeomAPI_Pnt2d> project(
+      const std::shared_ptr<GeomAPI_Pnt2d>& thePoint) const;
+
+  /** \brief Computes the parameter of a given point on an ellipse. The point must be
+   *         located either on the circle itself or relatively to the latter
+   *         at a distance less than the tolerance value. Return FALSE if the point
+   *         is beyond the tolerance limit or if computation fails.
+   *         Max Tolerance value is currently limited to 1.e-4
+   *  \param[in]  thePoint point of origin.
+   *  \param[in]  theTolerance tolerance of computation.
+   *  \param[out] theParameter resulting parameter.
+   */
+  GEOMAPI_EXPORT const bool parameter(const std::shared_ptr<GeomAPI_Pnt2d> thePoint,
+                                      const double theTolerance,
+                                      double& theParameter) const;
+
   /// Calculate minimal distance between the ellipse and a line.
   /// Return corresponding points on the ellipse and on the line.
   GEOMAPI_EXPORT double distance(const std::shared_ptr<GeomAPI_Lin2d>& theLine,
index 85828425c2aaee9eb5e56004d8c001554101eb30..9bfc1a50a20364ac3d8c4af28ca2c23fb34d9bd8 100644 (file)
 //
 
 #include <GeomAlgoAPI_EdgeBuilder.h>
+
+#include <GeomAPI_Ax2.h>
+#include <GeomAPI_Ellipse.h>
+
 #include <gp_Pln.hxx>
 #include <BRepBuilderAPI_MakeEdge.hxx>
 #include <TopoDS_Edge.hxx>
@@ -236,3 +240,29 @@ std::shared_ptr<GeomAPI_Edge> GeomAlgoAPI_EdgeBuilder::ellipse(
   aRes->setImpl(new TopoDS_Shape(anEdge));
   return aRes;
 }
+
+std::shared_ptr<GeomAPI_Edge> GeomAlgoAPI_EdgeBuilder::ellipticArc(
+    const std::shared_ptr<GeomAPI_Pnt>& theCenter,
+    const std::shared_ptr<GeomAPI_Dir>& theNormal,
+    const std::shared_ptr<GeomAPI_Dir>& theMajorAxis,
+    const double                        theMajorRadius,
+    const double                        theMinorRadius,
+    const std::shared_ptr<GeomAPI_Pnt>& theStart,
+    const std::shared_ptr<GeomAPI_Pnt>& theEnd)
+{
+  std::shared_ptr<GeomAPI_Ax2> anAx2(new GeomAPI_Ax2(theCenter, theNormal, theMajorAxis));
+  GeomAPI_Ellipse anEllipse(anAx2, theMajorRadius, theMinorRadius);
+
+  GeomPointPtr aStartPnt = anEllipse.project(theStart);
+  GeomPointPtr aEndPnt   = anEllipse.project(theEnd);
+
+  double aStartParam, aEndParam;
+  anEllipse.parameter(aStartPnt, Precision::Confusion(), aStartParam);
+  anEllipse.parameter(aEndPnt, Precision::Confusion(), aEndParam);
+
+  BRepBuilderAPI_MakeEdge anEdgeBuilder(anEllipse.impl<gp_Elips>(), aStartParam, aEndParam);
+  GeomEdgePtr aRes(new GeomAPI_Edge);
+  TopoDS_Edge anEdge = anEdgeBuilder.Edge();
+  aRes->setImpl(new TopoDS_Shape(anEdge));
+  return aRes;
+}
index 259800972bc6c6de42395a7c5d40a69ae1e0d67f..245e97f05888c0795f2d21e37dde3f242ae10e05 100644 (file)
@@ -78,6 +78,17 @@ class GEOMALGOAPI_EXPORT GeomAlgoAPI_EdgeBuilder
                                                const std::shared_ptr<GeomAPI_Dir>& theMajorAxis,
                                                const double                        theMajorRadius,
                                                const double                        theMinorRadius);
+
+
+  /// Creates elliptic edge
+  static std::shared_ptr<GeomAPI_Edge> ellipticArc(
+      const std::shared_ptr<GeomAPI_Pnt>& theCenter,
+      const std::shared_ptr<GeomAPI_Dir>& theNormal,
+      const std::shared_ptr<GeomAPI_Dir>& theMajorAxis,
+      const double                        theMajorRadius,
+      const double                        theMinorRadius,
+      const std::shared_ptr<GeomAPI_Pnt>& theStart,
+      const std::shared_ptr<GeomAPI_Pnt>& theEnd);
 };
 
 #endif
index d7274a96a900fc3e5378182c271abfe0eae1d16e..47508117cf95284165f6ada5f69096289bea238b 100644 (file)
@@ -47,6 +47,7 @@ SET(PROJECT_HEADERS
     SketchPlugin_ConstraintTangent.h
     SketchPlugin_ConstraintVertical.h
     SketchPlugin_Ellipse.h
+    SketchPlugin_EllipticArc.h
     SketchPlugin_ExternalValidator.h
     SketchPlugin_Feature.h
     SketchPlugin_IntersectionPoint.h
@@ -55,6 +56,7 @@ SET(PROJECT_HEADERS
     SketchPlugin_MacroArcReentrantMessage.h
     SketchPlugin_MacroCircle.h
     SketchPlugin_MacroEllipse.h
+    SketchPlugin_MacroEllipticArc.h
     SketchPlugin_MultiRotation.h
     SketchPlugin_MultiTranslation.h
     SketchPlugin_Plugin.h
@@ -94,6 +96,7 @@ SET(PROJECT_SOURCES
     SketchPlugin_ConstraintTangent.cpp
     SketchPlugin_ConstraintVertical.cpp
     SketchPlugin_Ellipse.cpp
+    SketchPlugin_EllipticArc.cpp
     SketchPlugin_ExternalValidator.cpp
     SketchPlugin_Feature.cpp
     SketchPlugin_IntersectionPoint.cpp
@@ -101,6 +104,7 @@ SET(PROJECT_SOURCES
     SketchPlugin_MacroArc.cpp
     SketchPlugin_MacroCircle.cpp
     SketchPlugin_MacroEllipse.cpp
+    SketchPlugin_MacroEllipticArc.cpp
     SketchPlugin_MultiRotation.cpp
     SketchPlugin_MultiTranslation.cpp
     SketchPlugin_Plugin.cpp
diff --git a/src/SketchPlugin/SketchPlugin_EllipticArc.cpp b/src/SketchPlugin/SketchPlugin_EllipticArc.cpp
new file mode 100644 (file)
index 0000000..3bc24f1
--- /dev/null
@@ -0,0 +1,223 @@
+// Copyright (C) 2017-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
+//
+
+#include <SketchPlugin_EllipticArc.h>
+#include <SketchPlugin_Sketch.h>
+
+#include <GeomAlgoAPI_EdgeBuilder.h>
+
+#include <GeomAPI_Dir2d.h>
+#include <GeomAPI_Edge.h>
+#include <GeomAPI_Ellipse.h>
+#include <GeomAPI_Pnt2d.h>
+
+#include <GeomDataAPI_Point2D.h>
+
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_ResultConstruction.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Validator.h>
+
+#include <cmath>
+
+static const double tolerance = 1e-7;
+
+
+SketchPlugin_EllipticArc::SketchPlugin_EllipticArc()
+: SketchPlugin_SketchEntity()
+{
+}
+
+void SketchPlugin_EllipticArc::initDerivedClassAttributes()
+{
+  data()->addAttribute(CENTER_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(FIRST_FOCUS_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(SECOND_FOCUS_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(MAJOR_AXIS_START_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(MAJOR_AXIS_END_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(MINOR_AXIS_START_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(MINOR_AXIS_END_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(MAJOR_RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
+  data()->addAttribute(MINOR_RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
+  data()->addAttribute(START_POINT_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(END_POINT_ID(), GeomDataAPI_Point2D::typeId());
+
+  data()->addAttribute(REVERSED_ID(), ModelAPI_AttributeBoolean::typeId());
+
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), SECOND_FOCUS_ID());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), MAJOR_AXIS_START_ID());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), MAJOR_AXIS_END_ID());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), MINOR_AXIS_START_ID());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), MINOR_AXIS_END_ID());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), MAJOR_RADIUS_ID());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), MINOR_RADIUS_ID());
+
+  data()->addAttribute(EXTERNAL_ID(), ModelAPI_AttributeSelection::typeId());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EXTERNAL_ID());
+}
+
+void SketchPlugin_EllipticArc::execute()
+{
+  SketchPlugin_Sketch* aSketch = sketch();
+  if(!aSketch) {
+    return;
+  }
+
+  // Calculate all characteristics of the ellipse.
+  fillCharacteristicPoints();
+
+  // Make a visible ellipse.
+  createEllipticArc(aSketch);
+}
+
+bool SketchPlugin_EllipticArc::isFixed() {
+  return data()->selection(EXTERNAL_ID())->context().get() != NULL;
+}
+
+void SketchPlugin_EllipticArc::attributeChanged(const std::string& theID) {
+  // the second condition for unability to move external segments anywhere
+  if (theID == EXTERNAL_ID() || isFixed()) {
+    std::shared_ptr<GeomAPI_Shape> aSelection = data()->selection(EXTERNAL_ID())->value();
+    if (!aSelection) {
+      // empty shape in selection shows that the shape is equal to context
+      ResultPtr anExtRes = selection(EXTERNAL_ID())->context();
+      if (anExtRes)
+        aSelection = anExtRes->shape();
+    }
+    // update arguments due to the selection value
+    if (aSelection && !aSelection->isNull() && aSelection->isEdge()) {
+      std::shared_ptr<GeomAPI_Edge> anEdge( new GeomAPI_Edge(aSelection));
+      std::shared_ptr<GeomAPI_Ellipse> anEllipse = anEdge->ellipse();
+
+      std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr =
+          std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_ID()));
+      aCenterAttr->setValue(sketch()->to2D(anEllipse->center()));
+
+      std::shared_ptr<GeomDataAPI_Point2D> aFocusAttr =
+          std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(FIRST_FOCUS_ID()));
+      aFocusAttr->setValue(sketch()->to2D(anEllipse->firstFocus()));
+
+      std::shared_ptr<GeomDataAPI_Point2D> aStartAttr =
+          std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(START_POINT_ID()));
+      aStartAttr->setValue(sketch()->to2D(anEdge->firstPoint()));
+
+      std::shared_ptr<GeomDataAPI_Point2D> aEndAttr =
+          std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(END_POINT_ID()));
+      aEndAttr->setValue(sketch()->to2D(anEdge->lastPoint()));
+
+      real(MAJOR_RADIUS_ID())->setValue(anEllipse->majorRadius());
+      real(MINOR_RADIUS_ID())->setValue(anEllipse->minorRadius());
+    }
+  }
+}
+
+bool SketchPlugin_EllipticArc::fillCharacteristicPoints()
+{
+  std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
+  std::shared_ptr<GeomDataAPI_Point2D> aFocusAttr =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(FIRST_FOCUS_ID()));
+
+  AttributeDoublePtr aMinorRadiusAttr = real(MINOR_RADIUS_ID());
+
+  if (!aCenterAttr->isInitialized() ||
+      !aFocusAttr->isInitialized() ||
+      !aMinorRadiusAttr->isInitialized()) {
+    return false;
+  }
+
+  double aMinorRadius = aMinorRadiusAttr->value();
+  if (aMinorRadius < tolerance) {
+    return false;
+  }
+
+  data()->blockSendAttributeUpdated(true);
+  GeomPnt2dPtr aCenter2d = aCenterAttr->pnt();
+  GeomPnt2dPtr aFocus2d = aFocusAttr->pnt();
+  GeomDir2dPtr aMajorDir2d(new GeomAPI_Dir2d(aFocus2d->x() - aCenter2d->x(),
+                                             aFocus2d->y() - aCenter2d->y()));
+  GeomDir2dPtr aMinorDir2d(new GeomAPI_Dir2d(-aMajorDir2d->y(), aMajorDir2d->x()));
+
+  AttributeDoublePtr aMajorRadiusAttr = real(MAJOR_RADIUS_ID());
+  double aFocalDist = aCenter2d->distance(aFocus2d);
+  double aMajorRadius = sqrt(aFocalDist * aFocalDist + aMinorRadius * aMinorRadius);
+  aMajorRadiusAttr->setValue(aMajorRadius);
+
+  std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(SECOND_FOCUS_ID()))
+    ->setValue(2.0 * aCenter2d->x() - aFocus2d->x(), 2.0 * aCenter2d->y() - aFocus2d->y());
+  std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(MAJOR_AXIS_START_ID()))
+      ->setValue(aCenter2d->x() - aMajorDir2d->x() * aMajorRadius,
+                 aCenter2d->y() - aMajorDir2d->y() * aMajorRadius);
+  std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(MAJOR_AXIS_END_ID()))
+      ->setValue(aCenter2d->x() + aMajorDir2d->x() * aMajorRadius,
+                 aCenter2d->y() + aMajorDir2d->y() * aMajorRadius);
+  std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(MINOR_AXIS_START_ID()))
+      ->setValue(aCenter2d->x() - aMinorDir2d->x() * aMinorRadius,
+                 aCenter2d->y() - aMinorDir2d->y() * aMinorRadius);
+  std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(MINOR_AXIS_END_ID()))
+      ->setValue(aCenter2d->x() + aMinorDir2d->x() * aMinorRadius,
+                 aCenter2d->y() + aMinorDir2d->y() * aMinorRadius);
+  data()->blockSendAttributeUpdated(false);
+
+  return true;
+}
+
+void SketchPlugin_EllipticArc::createEllipticArc(SketchPlugin_Sketch* theSketch)
+{
+  // Compute a ellipse in 3D view.
+  std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr =
+    std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
+  std::shared_ptr<GeomDataAPI_Point2D> aFocusAttr =
+    std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(FIRST_FOCUS_ID()));
+
+  double aMajorRadius = real(MAJOR_RADIUS_ID())->value();
+  double aMinorRadius = real(MINOR_RADIUS_ID())->value();
+
+  std::shared_ptr<GeomDataAPI_Dir> aNDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
+    theSketch->attribute(SketchPlugin_Sketch::NORM_ID()));
+
+  GeomPointPtr aCenter(theSketch->to3D(aCenterAttr->x(), aCenterAttr->y()));
+  GeomPointPtr aFocus(theSketch->to3D(aFocusAttr->x(), aFocusAttr->y()));
+  GeomDirPtr aNormal = aNDir->dir();
+  std::shared_ptr<GeomAPI_Shape> anEllipseShape;
+  if (aFocus->distance(aCenter) > tolerance) {
+    GeomDirPtr aMajorAxis(new GeomAPI_Dir(aFocus->x() - aCenter->x(),
+        aFocus->y() - aCenter->y(), aFocus->z() - aCenter->z()));
+
+    std::shared_ptr<GeomDataAPI_Point2D> aStartAttr =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(START_POINT_ID()));
+    std::shared_ptr<GeomDataAPI_Point2D> aEndAttr =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(END_POINT_ID()));
+
+    GeomPointPtr aStartPnt(theSketch->to3D(aStartAttr->x(), aStartAttr->y()));
+    GeomPointPtr aEndPnt(theSketch->to3D(aEndAttr->x(), aEndAttr->y()));
+
+    anEllipseShape = GeomAlgoAPI_EdgeBuilder::ellipticArc(aCenter, aNormal, aMajorAxis,
+        aMajorRadius, aMinorRadius, aStartPnt, aEndPnt);
+  }
+  else {
+    // build circle instead of ellipse
+    anEllipseShape = GeomAlgoAPI_EdgeBuilder::lineCircle(aCenter, aNormal, aMajorRadius);
+  }
+
+  ResultConstructionPtr aResult = document()->createConstruction(data());
+  aResult->setShape(anEllipseShape);
+  aResult->setIsInHistory(false);
+  setResult(aResult);
+}
diff --git a/src/SketchPlugin/SketchPlugin_EllipticArc.h b/src/SketchPlugin/SketchPlugin_EllipticArc.h
new file mode 100644 (file)
index 0000000..4b84d3b
--- /dev/null
@@ -0,0 +1,149 @@
+// Copyright (C) 2017-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
+//
+
+#ifndef SketchPlugin_EllipticArc_H_
+#define SketchPlugin_EllipticArc_H_
+
+#include <SketchPlugin.h>
+#include <SketchPlugin_SketchEntity.h>
+
+/**\class SketchPlugin_EllipticArc
+ * \ingroup Plugins
+ * \brief Feature for creation of the new elliptical arc in Sketch.
+ */
+class SketchPlugin_EllipticArc: public SketchPlugin_SketchEntity
+{
+ public:
+  /// Ellipse feature kind
+  inline static const std::string& ID()
+  {
+    static const std::string ID("SketchEllipticArc");
+    return ID;
+  }
+
+  /// 2D point - center of the ellipse
+  inline static const std::string& CENTER_ID()
+  {
+    static const std::string ID("ellipse_center");
+    return ID;
+  }
+
+  /// 2D point - start point of elliptic arc
+  inline static const std::string& START_POINT_ID()
+  {
+    static const std::string ID("start_point");
+    return ID;
+  }
+  /// 2D point - end point of elliptic arc
+  inline static const std::string& END_POINT_ID()
+  {
+    static const std::string ID("end_point");
+    return ID;
+  }
+
+  /// 2D point - focus of the ellipse
+  inline static const std::string& FIRST_FOCUS_ID()
+  {
+    static const std::string ID("ellipse_first_focus");
+    return ID;
+  }
+  /// 2D point - second focus of the ellipse
+  inline static const std::string& SECOND_FOCUS_ID()
+  {
+    static const std::string ID("ellipse_second_focus");
+    return ID;
+  }
+
+  /// 2D point - start point of major axis
+  inline static const std::string& MAJOR_AXIS_START_ID()
+  {
+    static const std::string ID("ellipse_major_axis_start_point");
+    return ID;
+  }
+  /// 2D point - end point of major axis
+  inline static const std::string& MAJOR_AXIS_END_ID()
+  {
+    static const std::string ID("ellipse_major_axis_end_point");
+    return ID;
+  }
+
+  /// 2D point - start point of minor axis
+  inline static const std::string& MINOR_AXIS_START_ID()
+  {
+    static const std::string ID("ellipse_minor_axis_start_point");
+    return ID;
+  }
+  /// 2D point - end point of minor axis
+  inline static const std::string& MINOR_AXIS_END_ID()
+  {
+    static const std::string ID("ellipse_minor_axis_end_point");
+    return ID;
+  }
+
+  /// Major radius of the ellipse
+  inline static const std::string& MAJOR_RADIUS_ID()
+  {
+    static const std::string ID("ellipse_major_radius");
+    return ID;
+  }
+
+  /// Minor radius of the ellipse
+  inline static const std::string& MINOR_RADIUS_ID()
+  {
+    static const std::string ID("ellipse_minor_radius");
+    return ID;
+  }
+
+  /// Flag the arc is reversed
+  inline static const std::string& REVERSED_ID()
+  {
+    static const std::string ID("reversed");
+    return ID;
+  }
+
+  /// Returns the kind of a feature
+  SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
+  {
+    static std::string MY_KIND = SketchPlugin_EllipticArc::ID();
+    return MY_KIND;
+  }
+
+  /// Returns true is sketch element is under the rigid constraint
+  SKETCHPLUGIN_EXPORT virtual bool isFixed();
+
+  /// Called on change of any argument-attribute of this object
+  SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID);
+
+  /// Creates a new part document if needed
+  SKETCHPLUGIN_EXPORT virtual void execute();
+
+  /// Use plugin manager for features creation
+  SketchPlugin_EllipticArc();
+
+protected:
+  /// \brief Initializes attributes of derived class.
+  virtual void initDerivedClassAttributes();
+
+private:
+  bool fillCharacteristicPoints();
+
+  void createEllipticArc(SketchPlugin_Sketch* theSketch);
+};
+
+#endif
index 99910cebaf0704d4b6cc90c00a518b39005a0535..a4abe7b7dd3a05eea839bfcd3bb2a0fb00990891 100644 (file)
@@ -295,84 +295,31 @@ FeaturePtr SketchPlugin_MacroEllipse::createEllipseFeature()
   aEllipseFeature->execute();
 
   // create auxiliary points
-  createAuxiliaryPoint(aEllipseFeature, SketchPlugin_Ellipse::CENTER_ID());
-  createAuxiliaryPoint(aEllipseFeature, SketchPlugin_Ellipse::FIRST_FOCUS_ID());
-  createAuxiliaryPoint(aEllipseFeature, SketchPlugin_Ellipse::SECOND_FOCUS_ID());
-  createAuxiliaryPoint(aEllipseFeature, SketchPlugin_Ellipse::MAJOR_AXIS_START_ID());
-  createAuxiliaryPoint(aEllipseFeature, SketchPlugin_Ellipse::MAJOR_AXIS_END_ID());
-  createAuxiliaryPoint(aEllipseFeature, SketchPlugin_Ellipse::MINOR_AXIS_START_ID());
-  createAuxiliaryPoint(aEllipseFeature, SketchPlugin_Ellipse::MINOR_AXIS_END_ID());
+  SketchPlugin_Tools::createAuxiliaryPointOnEllipse(
+      aEllipseFeature, SketchPlugin_Ellipse::CENTER_ID());
+  SketchPlugin_Tools::createAuxiliaryPointOnEllipse(
+      aEllipseFeature, SketchPlugin_Ellipse::FIRST_FOCUS_ID());
+  SketchPlugin_Tools::createAuxiliaryPointOnEllipse(
+      aEllipseFeature, SketchPlugin_Ellipse::SECOND_FOCUS_ID());
+  SketchPlugin_Tools::createAuxiliaryPointOnEllipse(
+      aEllipseFeature, SketchPlugin_Ellipse::MAJOR_AXIS_START_ID());
+  SketchPlugin_Tools::createAuxiliaryPointOnEllipse(
+      aEllipseFeature, SketchPlugin_Ellipse::MAJOR_AXIS_END_ID());
+  SketchPlugin_Tools::createAuxiliaryPointOnEllipse(
+      aEllipseFeature, SketchPlugin_Ellipse::MINOR_AXIS_START_ID());
+  SketchPlugin_Tools::createAuxiliaryPointOnEllipse(
+      aEllipseFeature, SketchPlugin_Ellipse::MINOR_AXIS_END_ID());
   // create auxiliary axes
-  createAuxiliaryAxis(aEllipseFeature,
+  SketchPlugin_Tools::createAuxiliaryAxisOfEllipse(aEllipseFeature,
                       SketchPlugin_Ellipse::MAJOR_AXIS_START_ID(),
                       SketchPlugin_Ellipse::MAJOR_AXIS_END_ID());
-  createAuxiliaryAxis(aEllipseFeature,
+  SketchPlugin_Tools::createAuxiliaryAxisOfEllipse(aEllipseFeature,
                       SketchPlugin_Ellipse::MINOR_AXIS_START_ID(),
                       SketchPlugin_Ellipse::MINOR_AXIS_END_ID());
 
   return aEllipseFeature;
 }
 
-void SketchPlugin_MacroEllipse::createAuxiliaryPoint(const FeaturePtr& theEllipseFeature,
-                                                     const std::string& theEllipsePoint)
-{
-  FeaturePtr aPointFeature = sketch()->addFeature(SketchPlugin_Point::ID());
-  aPointFeature->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(true);
-  aPointFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theEllipseFeature);
-
-  AttributePoint2DPtr anElPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theEllipseFeature->attribute(theEllipsePoint));
-
-  AttributePoint2DPtr aCoord = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      aPointFeature->attribute(SketchPlugin_Point::COORD_ID()));
-  aCoord->setValue(anElPoint->x(), anElPoint->y());
-
-  aPointFeature->execute();
-  std::string aName = theEllipseFeature->name() + "_" + theEllipsePoint;
-  aPointFeature->data()->setName(aName);
-  aPointFeature->lastResult()->data()->setName(aName);
-
-  createInternalConstraint(anElPoint, aCoord);
-}
-
-void SketchPlugin_MacroEllipse::createAuxiliaryAxis(const FeaturePtr& theEllipseFeature,
-                                                    const std::string& theStartPoint,
-                                                    const std::string& theEndPoint)
-{
-  FeaturePtr aLineFeature = sketch()->addFeature(SketchPlugin_Line::ID());
-  aLineFeature->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(true);
-  aLineFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theEllipseFeature);
-
-  AttributePoint2DPtr aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theEllipseFeature->attribute(theStartPoint));
-  AttributePoint2DPtr aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theEllipseFeature->attribute(theEndPoint));
-
-  AttributePoint2DPtr aLineStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      aLineFeature->attribute(SketchPlugin_Line::START_ID()));
-  aLineStart->setValue(aStartPoint->x(), aStartPoint->y());
-
-  AttributePoint2DPtr aLineEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      aLineFeature->attribute(SketchPlugin_Line::END_ID()));
-  aLineEnd->setValue(aEndPoint->x(), aEndPoint->y());
-
-  aLineFeature->execute();
-  std::string aName = theEllipseFeature->name() + "_" +
-      (theStartPoint == SketchPlugin_Ellipse::MAJOR_AXIS_START_ID() ? "major_axis" : "minor_axis");
-  aLineFeature->data()->setName(aName);
-  aLineFeature->lastResult()->data()->setName(aName);
-
-  createInternalConstraint(aStartPoint, aLineStart);
-  createInternalConstraint(aEndPoint, aLineEnd);
-}
-
-void SketchPlugin_MacroEllipse::createInternalConstraint(const AttributePtr& thePoint1,
-                                                         const AttributePtr& thePoint2)
-{
-  SketchPlugin_Tools::createConstraintAttrAttr(
-      sketch(), SketchPlugin_ConstraintCoincidenceInternal::ID(), thePoint1, thePoint2);
-}
-
 AISObjectPtr SketchPlugin_MacroEllipse::getAISObject(AISObjectPtr thePrevious)
 {
   SketchPlugin_Sketch* aSketch = sketch();
index 4bea22221d0ad0aa44f24c9aa6d7ed403caea2c4..609d96bf6b0315532f56e35e8d12b9518498452e 100644 (file)
@@ -162,14 +162,6 @@ private:
 
   FeaturePtr createEllipseFeature();
 
-  void createAuxiliaryPoint(const FeaturePtr& theEllipseFeature,
-                            const std::string& theEllipsePoint);
-  void createAuxiliaryAxis(const FeaturePtr& theEllipseFeature,
-                           const std::string& theStartPoint,
-                           const std::string& theEndPoint);
-
-  void createInternalConstraint(const AttributePtr& thePoint1, const AttributePtr& thePoint2);
-
 private:
   std::shared_ptr<GeomAPI_Pnt2d> myCenter;
   std::shared_ptr<GeomAPI_Pnt2d> myFocus;
diff --git a/src/SketchPlugin/SketchPlugin_MacroEllipticArc.cpp b/src/SketchPlugin/SketchPlugin_MacroEllipticArc.cpp
new file mode 100644 (file)
index 0000000..768e827
--- /dev/null
@@ -0,0 +1,413 @@
+// Copyright (C) 2017-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
+//
+
+#include <SketchPlugin_MacroEllipticArc.h>
+
+////#include <SketchPlugin_ConstraintCoincidenceInternal.h>
+#include <SketchPlugin_EllipticArc.h>
+////#include <SketchPlugin_Line.h>
+#include <SketchPlugin_MacroArcReentrantMessage.h>
+////#include <SketchPlugin_Point.h>
+#include <SketchPlugin_Tools.h>
+#include <SketchPlugin_Sketch.h>
+
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeRefAttr.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Validator.h>
+#include <ModelAPI_Events.h>
+
+#include <GeomDataAPI_Point2D.h>
+
+#include <GeomAPI_Dir2d.h>
+#include <GeomAPI_Ellipse.h>
+#include <GeomAPI_Ellipse2d.h>
+#include <GeomAPI_Vertex.h>
+
+#include <GeomAlgoAPI_CompoundBuilder.h>
+#include <GeomAlgoAPI_EdgeBuilder.h>
+#include <GeomAlgoAPI_PointBuilder.h>
+
+
+const double paramTolerance = 1.e-4;
+const double PI = 3.141592653589793238463;
+
+
+SketchPlugin_MacroEllipticArc::SketchPlugin_MacroEllipticArc()
+  : SketchPlugin_SketchEntity(),
+    myMajorRadius(0.0),
+    myMinorRadius(0.0),
+    myParamDelta(0.0)
+{
+}
+
+void SketchPlugin_MacroEllipticArc::initAttributes()
+{
+  data()->addAttribute(CENTER_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(CENTER_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
+  data()->addAttribute(MAJOR_AXIS_POINT_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(MAJOR_AXIS_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
+  data()->addAttribute(START_POINT_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(START_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
+  data()->addAttribute(END_POINT_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(END_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
+
+  data()->addAttribute(MAJOR_RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
+  data()->addAttribute(MINOR_RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
+
+  data()->addAttribute(REVERSED_ID(), ModelAPI_AttributeBoolean::typeId());
+  data()->addAttribute(AUXILIARY_ID(), ModelAPI_AttributeBoolean::typeId());
+
+  boolean(REVERSED_ID())->setValue(false);
+
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), CENTER_REF_ID());
+  ModelAPI_Session::get()->validators()
+      ->registerNotObligatory(getKind(), MAJOR_AXIS_POINT_REF_ID());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), START_POINT_REF_ID());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), END_POINT_REF_ID());
+}
+
+void SketchPlugin_MacroEllipticArc::execute()
+{
+  FeaturePtr anEllipse = createEllipticArcFeature();
+
+  // message to init reentrant operation
+  static Events_ID anId = SketchPlugin_MacroArcReentrantMessage::eventId();
+  std::shared_ptr<SketchPlugin_MacroArcReentrantMessage> aMessage = std::shared_ptr
+    <SketchPlugin_MacroArcReentrantMessage>(new SketchPlugin_MacroArcReentrantMessage(anId, this));
+  aMessage->setCreatedFeature(anEllipse);
+  Events_Loop::loop()->send(aMessage);
+}
+
+void SketchPlugin_MacroEllipticArc::attributeChanged(const std::string& theID)
+{
+  static const int NB_POINTS = 4;
+  std::string aPointAttrName[NB_POINTS] = { CENTER_ID(),
+                                            MAJOR_AXIS_POINT_ID(),
+                                            START_POINT_ID(),
+                                            END_POINT_ID() };
+  std::string aPointRefName[NB_POINTS] = { CENTER_REF_ID(),
+                                           MAJOR_AXIS_POINT_REF_ID(),
+                                           START_POINT_REF_ID(),
+                                           END_POINT_REF_ID() };
+
+  int aNbInitialized = 0;
+  GeomPnt2dPtr anEllipsePoints[NB_POINTS];
+
+  for (int aPntIndex = 0; aPntIndex < NB_POINTS; ++aPntIndex) {
+    AttributePtr aPointAttr = attribute(aPointAttrName[aPntIndex]);
+    if (!aPointAttr->isInitialized())
+      continue;
+
+    AttributeRefAttrPtr aPointRef = refattr(aPointRefName[aPntIndex]);
+    // calculate ellipse parameters
+    GeomPnt2dPtr aPassedPoint =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPointAttr)->pnt();
+    GeomShapePtr aTangentCurve;
+    SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
+      aPointRef, aPointAttr, aTangentCurve, aPassedPoint);
+
+    anEllipsePoints[aNbInitialized++] = aPassedPoint;
+  }
+
+  if (aNbInitialized <= 1)
+    return; // too few points for the ellipse
+
+  myCenter    = anEllipsePoints[0];
+  myMajorAxis = anEllipsePoints[1];
+  myStartPnt  = anEllipsePoints[2];
+  myEndPnt    = anEllipsePoints[3];
+
+  std::shared_ptr<GeomAPI_Ellipse2d> anEllipse;
+  if (aNbInitialized == 2) {
+    GeomDir2dPtr aXDir(new GeomAPI_Dir2d(anEllipsePoints[1]->x() - anEllipsePoints[0]->x(),
+                                         anEllipsePoints[1]->y() - anEllipsePoints[0]->y()));
+    double aMajorRad = anEllipsePoints[1]->distance(anEllipsePoints[0]);
+    anEllipse = std::shared_ptr<GeomAPI_Ellipse2d>(
+        new GeomAPI_Ellipse2d(anEllipsePoints[0], aXDir, aMajorRad, 0.5 * aMajorRad));
+  }
+  else if (aNbInitialized >= 3) {
+    anEllipse = std::shared_ptr<GeomAPI_Ellipse2d>(
+      new GeomAPI_Ellipse2d(anEllipsePoints[0], anEllipsePoints[1], anEllipsePoints[2]));
+  }
+
+  if (!anEllipse || anEllipse->implPtr<void>() == 0)
+    return;
+
+  myMajorRadius = anEllipse->majorRadius();
+  myMinorRadius = anEllipse->minorRadius();
+
+  bool aWasBlocked = data()->blockSendAttributeUpdated(true);
+  real(MAJOR_RADIUS_ID())->setValue(myMajorRadius);
+  real(MINOR_RADIUS_ID())->setValue(myMinorRadius);
+  data()->blockSendAttributeUpdated(aWasBlocked, false);
+
+  // update the REVERSED flag
+  if (myEndPnt) {
+    double aParameterEnd = 0.0;
+    GeomPnt2dPtr aEnd = anEllipse->project(myEndPnt);
+    if (anEllipse->parameter(aEnd, paramTolerance, aParameterEnd)) {
+      double aParamStart = 0.0;
+      anEllipse->parameter(myStartPnt, paramTolerance, aParamStart);
+      aParameterEnd -= aParamStart;
+
+      if (myParamDelta > 0.0 && myParamDelta <= PI * 0.5 &&
+          aParameterEnd < 0 && aParameterEnd >= -PI * 0.5) {
+        boolean(REVERSED_ID())->setValue(true);
+      }
+      else if (myParamDelta < 0.0 && myParamDelta >= -PI * 0.5 &&
+               aParameterEnd > 0.0 && aParameterEnd <= PI * 0.5) {
+        boolean(REVERSED_ID())->setValue(false);
+      }
+    }
+    myParamDelta = aParameterEnd;
+  }
+}
+
+// LCOV_EXCL_START
+std::string SketchPlugin_MacroEllipticArc::processEvent(
+                                              const std::shared_ptr<Events_Message>& theMessage)
+{
+  std::string aFilledAttributeName;
+
+  std::shared_ptr<SketchPlugin_MacroArcReentrantMessage> aReentrantMessage =
+      std::dynamic_pointer_cast<SketchPlugin_MacroArcReentrantMessage>(theMessage);
+  if (aReentrantMessage) {
+    FeaturePtr aCreatedFeature = aReentrantMessage->createdFeature();
+
+    ObjectPtr anObject = aReentrantMessage->selectedObject();
+    AttributePtr anAttribute = aReentrantMessage->selectedAttribute();
+    std::shared_ptr<GeomAPI_Pnt2d> aClickedPoint = aReentrantMessage->clickedPoint();
+
+    if (aClickedPoint && (anObject || anAttribute)) {
+      aFilledAttributeName = CENTER_ID();
+      std::string aReferenceAttributeName = CENTER_REF_ID();
+
+      // fill 2d point attribute
+      AttributePoint2DPtr aPointAttr =
+          std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(aFilledAttributeName));
+      aPointAttr->setValue(aClickedPoint);
+
+      // fill reference attribute
+      AttributeRefAttrPtr aRefAttr =
+          std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(attribute(aReferenceAttributeName));
+      if (anAttribute) {
+        if (!anAttribute->owner() || !anAttribute->owner()->data()->isValid()) {
+          if (aCreatedFeature && anAttribute->id() == CENTER_ID())
+            anAttribute = aCreatedFeature->attribute(SketchPlugin_EllipticArc::CENTER_ID());
+        }
+        aRefAttr->setAttr(anAttribute);
+      }
+      else if (anObject.get()) {
+        // if attribute is NULL, only object is defined, it should be processed outside
+        // the feature because it might be an external feature, that will be
+        // removed/created again after restart operation
+        // #2468 - Crash when sketching circles successively on a repetition
+        aFilledAttributeName = "";
+      }
+    }
+    Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
+  }
+  return aFilledAttributeName;
+}
+// LCOV_EXCL_STOP
+
+////void SketchPlugin_MacroEllipticArc::constraintsForEllipseByCenterAxisAndPassed(
+////    FeaturePtr theEllipseFeature)
+////{
+////  // tangency on-the-fly is not applicable for ellipses
+////  static const bool isTangencyApplicable = false;
+////  // Create constraints.
+////  SketchPlugin_Tools::createCoincidenceOrTangency(
+////      this, FIRST_POINT_REF_ID(),
+////      theEllipseFeature->attribute(SketchPlugin_Ellipse::CENTER_ID()),
+////      ObjectPtr(), isTangencyApplicable);
+////  SketchPlugin_Tools::createCoincidenceOrTangency(
+////      this, SECOND_POINT_REF_ID(),
+////      theEllipseFeature->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_END_ID()),
+////      ObjectPtr(), isTangencyApplicable);
+////  // make coincidence only if PASSED_POINT_REF_ID() refers a point but not an object
+////  if (!refattr(PASSED_POINT_REF_ID())->isObject()) {
+////    SketchPlugin_Tools::createCoincidenceOrTangency(
+////        this, PASSED_POINT_REF_ID(), AttributePtr(),
+////        theEllipseFeature->lastResult(), isTangencyApplicable);
+////  }
+////}
+////
+////void SketchPlugin_MacroEllipticArc::constraintsForEllipseByMajoxAxisAndPassed(
+////    FeaturePtr theEllipseFeature)
+////{
+////  // tangency on-the-fly is not applicable for ellipses
+////  static const bool isTangencyApplicable = false;
+////  // Create constraints.
+////  SketchPlugin_Tools::createCoincidenceOrTangency(
+////      this, FIRST_POINT_REF_ID(),
+////      theEllipseFeature->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_START_ID()),
+////      ObjectPtr(), isTangencyApplicable);
+////  SketchPlugin_Tools::createCoincidenceOrTangency(
+////      this, SECOND_POINT_REF_ID(),
+////      theEllipseFeature->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_END_ID()),
+////      ObjectPtr(), isTangencyApplicable);
+////  // make coincidence only if PASSED_POINT_REF_ID() refers a point but not an object
+////  if (!refattr(PASSED_POINT_REF_ID())->isObject()) {
+////    SketchPlugin_Tools::createCoincidenceOrTangency(
+////        this, PASSED_POINT_REF_ID(), AttributePtr(),
+////        theEllipseFeature->lastResult(), isTangencyApplicable);
+////  }
+////}
+
+FeaturePtr SketchPlugin_MacroEllipticArc::createEllipticArcFeature()
+{
+  GeomShapePtr anArc = getArcShape();
+  GeomEllipsePtr anEllipse;
+  GeomPointPtr aStartPoint, aEndPoint;
+  if (anArc->isEdge()) {
+    GeomEdgePtr anArcEdge = anArc->edge();
+    aStartPoint = anArcEdge->firstPoint();
+    aEndPoint = anArcEdge->lastPoint();
+
+    if (anArcEdge->isEllipse())
+      anEllipse = anArcEdge->ellipse();
+  }
+
+  if (!anEllipse)
+    return FeaturePtr();
+
+  // Create and fill new EllipticArc feature
+  SketchPlugin_Sketch* aSketch = sketch();
+  FeaturePtr aEllipseFeature = aSketch->addFeature(SketchPlugin_EllipticArc::ID());
+
+  AttributePoint2DPtr aCenterAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aEllipseFeature->attribute(SketchPlugin_EllipticArc::CENTER_ID()));
+  aCenterAttr->setValue(aSketch->to2D(anEllipse->center()));
+
+  AttributePoint2DPtr aFocusAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aEllipseFeature->attribute(SketchPlugin_EllipticArc::FIRST_FOCUS_ID()));
+  aFocusAttr->setValue(aSketch->to2D(anEllipse->firstFocus()));
+
+  AttributePoint2DPtr aStartAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aEllipseFeature->attribute(SketchPlugin_EllipticArc::START_POINT_ID()));
+  aStartAttr->setValue(aSketch->to2D(aStartPoint));
+
+  AttributePoint2DPtr aEndAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aEllipseFeature->attribute(SketchPlugin_EllipticArc::END_POINT_ID()));
+  aEndAttr->setValue(aSketch->to2D(aEndPoint));
+
+  aEllipseFeature->real(SketchPlugin_EllipticArc::MAJOR_RADIUS_ID())->setValue(myMajorRadius);
+  aEllipseFeature->real(SketchPlugin_EllipticArc::MINOR_RADIUS_ID())->setValue(myMinorRadius);
+
+  aEllipseFeature->boolean(SketchPlugin_EllipticArc::REVERSED_ID())->setValue(
+      boolean(REVERSED_ID())->value());
+
+  aEllipseFeature->boolean(SketchPlugin_EllipticArc::AUXILIARY_ID())->setValue(
+      boolean(AUXILIARY_ID())->value());
+
+  aEllipseFeature->execute();
+
+  // create auxiliary points
+  SketchPlugin_Tools::createAuxiliaryPointOnEllipse(
+      aEllipseFeature, SketchPlugin_EllipticArc::CENTER_ID());
+  SketchPlugin_Tools::createAuxiliaryPointOnEllipse(
+      aEllipseFeature, SketchPlugin_EllipticArc::FIRST_FOCUS_ID());
+  SketchPlugin_Tools::createAuxiliaryPointOnEllipse(
+      aEllipseFeature, SketchPlugin_EllipticArc::SECOND_FOCUS_ID());
+  SketchPlugin_Tools::createAuxiliaryPointOnEllipse(
+      aEllipseFeature, SketchPlugin_EllipticArc::MAJOR_AXIS_START_ID());
+  SketchPlugin_Tools::createAuxiliaryPointOnEllipse(
+      aEllipseFeature, SketchPlugin_EllipticArc::MAJOR_AXIS_END_ID());
+  SketchPlugin_Tools::createAuxiliaryPointOnEllipse(
+      aEllipseFeature, SketchPlugin_EllipticArc::MINOR_AXIS_START_ID());
+  SketchPlugin_Tools::createAuxiliaryPointOnEllipse(
+      aEllipseFeature, SketchPlugin_EllipticArc::MINOR_AXIS_END_ID());
+  // create auxiliary axes
+  SketchPlugin_Tools::createAuxiliaryAxisOfEllipse(aEllipseFeature,
+                      SketchPlugin_EllipticArc::MAJOR_AXIS_START_ID(),
+                      SketchPlugin_EllipticArc::MAJOR_AXIS_END_ID());
+  SketchPlugin_Tools::createAuxiliaryAxisOfEllipse(aEllipseFeature,
+                      SketchPlugin_EllipticArc::MINOR_AXIS_START_ID(),
+                      SketchPlugin_EllipticArc::MINOR_AXIS_END_ID());
+
+  return aEllipseFeature;
+}
+
+AISObjectPtr SketchPlugin_MacroEllipticArc::getAISObject(AISObjectPtr thePrevious)
+{
+  SketchPlugin_Sketch* aSketch = sketch();
+  if (!aSketch || !myCenter || !myMajorAxis)
+    return AISObjectPtr();
+
+  // Compute a elliptic arc in 3D view.
+  GeomPointPtr aCenter(aSketch->to3D(myCenter->x(), myCenter->y()));
+  GeomShapePtr aCenterPointShape = GeomAlgoAPI_PointBuilder::vertex(aCenter);
+  GeomShapePtr anArcShape = getArcShape();
+  if (!anArcShape.get() || !aCenterPointShape.get())
+    return AISObjectPtr();
+
+  std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
+  aShapes.push_back(anArcShape);
+  aShapes.push_back(aCenterPointShape);
+
+  std::shared_ptr<GeomAPI_Shape> aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
+  AISObjectPtr anAIS = thePrevious;
+  if (!anAIS)
+    anAIS.reset(new GeomAPI_AISObject());
+  anAIS->createShape(aCompound);
+  return anAIS;
+}
+
+GeomShapePtr SketchPlugin_MacroEllipticArc::getArcShape()
+{
+  if (!myCenter.get() || !myMajorAxis.get())
+    return GeomShapePtr();
+
+  SketchPlugin_Sketch* aSketch = sketch();
+  if (!aSketch)
+    return GeomShapePtr();
+
+  GeomPointPtr aCenter(aSketch->to3D(myCenter->x(), myCenter->y()));
+  GeomPointPtr aMajorAxisPnt(aSketch->to3D(myMajorAxis->x(), myMajorAxis->y()));
+  GeomDirPtr aMajorAxisDir(new GeomAPI_Dir(aMajorAxisPnt->x() - aCenter->x(),
+                                           aMajorAxisPnt->y() - aCenter->y(),
+                                           aMajorAxisPnt->z() - aCenter->z()));
+
+  std::shared_ptr<GeomDataAPI_Dir> aNDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
+      aSketch->attribute(SketchPlugin_Sketch::NORM_ID()));
+  GeomDirPtr aNormal(new GeomAPI_Dir(aNDir->x(), aNDir->y(), aNDir->z()));
+
+  GeomPointPtr aStart, anEnd;
+  if (myStartPnt)
+    aStart = aSketch->to3D(myStartPnt->x(), myStartPnt->y());
+  if (myEndPnt)
+    anEnd = aSketch->to3D(myEndPnt->x(), myEndPnt->y());
+
+  GeomShapePtr anArcShape;
+  if (anEnd) {
+    if (boolean(REVERSED_ID())->value())
+      std::swap(aStart, anEnd);
+
+    anArcShape = GeomAlgoAPI_EdgeBuilder::ellipticArc(aCenter, aNormal, aMajorAxisDir,
+        myMajorRadius, myMinorRadius, aStart, anEnd);
+  }
+  else {
+    anArcShape = GeomAlgoAPI_EdgeBuilder::ellipse(aCenter, aNormal, aMajorAxisDir,
+        myMajorRadius, myMinorRadius);
+  }
+
+  return anArcShape;
+}
diff --git a/src/SketchPlugin/SketchPlugin_MacroEllipticArc.h b/src/SketchPlugin/SketchPlugin_MacroEllipticArc.h
new file mode 100644 (file)
index 0000000..1d6db5f
--- /dev/null
@@ -0,0 +1,176 @@
+// Copyright (C) 2017-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
+//
+
+#ifndef SketchPlugin_MacroEllipticArc_H_
+#define SketchPlugin_MacroEllipticArc_H_
+
+#include <ModelAPI_IReentrant.h>
+#include <SketchPlugin.h>
+#include <SketchPlugin_SketchEntity.h>
+#include <GeomAPI_IPresentable.h>
+
+class GeomAPI_Pnt2d;
+class GeomAPI_Shape;
+
+/**\class SketchPlugin_MacroEllipticArc
+ * \ingroup Plugins
+ * \brief Feature for creation of the new elliptical arc in Sketch.
+ */
+class SketchPlugin_MacroEllipticArc: public SketchPlugin_SketchEntity,
+                                     public GeomAPI_IPresentable,
+                                     public ModelAPI_IReentrant
+{
+ public:
+  /// Elliptical arc feature kind
+  inline static const std::string& ID()
+  {
+    static const std::string ID("SketchMacroEllipticArc");
+    return ID;
+  }
+
+  /// Attribute for the central point selected during elliptic arc creation.
+  inline static const std::string& CENTER_ID()
+  {
+    static const std::string ID("center");
+    return ID;
+  }
+
+  /// Reference to the first selected point (center of ellipse).
+  inline static const std::string& CENTER_REF_ID()
+  {
+    static const std::string ID("center_ref");
+    return ID;
+  }
+
+  /// Attribute for the point on major semi-axis selected during elliptic arc creation.
+  inline static const std::string& MAJOR_AXIS_POINT_ID()
+  {
+    static const std::string ID("major_axis_point");
+    return ID;
+  }
+
+  /// Reference to the second selected point (major semi-axis of the ellipse).
+  inline static const std::string& MAJOR_AXIS_POINT_REF_ID()
+  {
+    static const std::string ID("major_axis_point_ref");
+    return ID;
+  }
+
+  /// Attribute for the start point of the elliptic arc selected during creation.
+  inline static const std::string& START_POINT_ID()
+  {
+    static const std::string ID("start_point");
+    return ID;
+  }
+
+  /// Reference for the start point selection.
+  inline static const std::string& START_POINT_REF_ID()
+  {
+    static const std::string ID("start_point_ref");
+    return ID;
+  }
+
+  /// Attribute for the end point of the elliptic arc selected during creation.
+  inline static const std::string& END_POINT_ID()
+  {
+    static const std::string ID("end_point");
+    return ID;
+  }
+
+  /// Reference for the end point selection.
+  inline static const std::string& END_POINT_REF_ID()
+  {
+    static const std::string ID("end_point_ref");
+    return ID;
+  }
+
+  /// Major radius of the ellipse
+  inline static const std::string& MAJOR_RADIUS_ID()
+  {
+    static const std::string ID("major_radius");
+    return ID;
+  }
+
+  /// Minor radius of the ellipse
+  inline static const std::string& MINOR_RADIUS_ID()
+  {
+    static const std::string ID("minor_radius");
+    return ID;
+  }
+
+  /// Flag the arc is reversed
+  inline static const std::string& REVERSED_ID()
+  {
+    static const std::string ID("reversed");
+    return ID;
+  }
+
+  /// Returns the kind of a feature
+  SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
+  {
+    static std::string MY_KIND = SketchPlugin_MacroEllipticArc::ID();
+    return MY_KIND;
+  }
+
+  /// \brief Request for initialization of data model of the feature: adding all attributes.
+  SKETCHPLUGIN_EXPORT virtual void initAttributes();
+
+  /// Called on change of any argument-attribute of this object
+  SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID);
+
+  /// Returns the AIS preview
+  virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious);
+
+  /// Creates a new part document if needed
+  SKETCHPLUGIN_EXPORT virtual void execute();
+
+  /// Reimplemented from ModelAPI_Feature::isMacro().
+  /// \returns true
+  SKETCHPLUGIN_EXPORT virtual bool isMacro() const
+  {return true;}
+
+  SKETCHPLUGIN_EXPORT virtual bool isPreviewNeeded() const
+  {return false;}
+
+  /// Apply information of the message to current object. It fills reference object,
+  /// tangent type and tangent point refence in case of tangent arc
+  virtual std::string processEvent(const std::shared_ptr<Events_Message>& theMessage);
+
+  /// Use plugin manager for features creation
+  SketchPlugin_MacroEllipticArc();
+
+private:
+  std::shared_ptr<GeomAPI_Shape> getArcShape();
+
+////  void constraintsForEllipseByCenterAxisAndPassed(FeaturePtr theEllipseFeature);
+////  void constraintsForEllipseByMajoxAxisAndPassed(FeaturePtr theEllipseFeature);
+
+  FeaturePtr createEllipticArcFeature();
+
+private:
+  std::shared_ptr<GeomAPI_Pnt2d> myCenter;
+  std::shared_ptr<GeomAPI_Pnt2d> myMajorAxis;
+  std::shared_ptr<GeomAPI_Pnt2d> myStartPnt;
+  std::shared_ptr<GeomAPI_Pnt2d> myEndPnt;
+  double myMajorRadius;
+  double myMinorRadius;
+  double myParamDelta;
+};
+
+#endif
index 38852d714517ec9a8c50455ba721920789588415..d9e967e60a7e7f07a18eea5fba7f0de76e47a31d 100644 (file)
@@ -54,6 +54,8 @@
 #include <SketchPlugin_ExternalValidator.h>
 #include <SketchPlugin_Ellipse.h>
 #include <SketchPlugin_MacroEllipse.h>
+#include <SketchPlugin_EllipticArc.h>
+#include <SketchPlugin_MacroEllipticArc.h>
 #include <SketchPlugin_SketchDrawer.h>
 
 #include <SketcherPrs_Tools.h>
@@ -251,6 +253,10 @@ FeaturePtr SketchPlugin_Plugin::createFeature(std::string theFeatureID)
     return FeaturePtr(new SketchPlugin_Ellipse);
   } else if (theFeatureID == SketchPlugin_MacroEllipse::ID()) {
     return FeaturePtr(new SketchPlugin_MacroEllipse);
+  } else if (theFeatureID == SketchPlugin_EllipticArc::ID()) {
+    return FeaturePtr(new SketchPlugin_EllipticArc);
+  } else if (theFeatureID == SketchPlugin_MacroEllipticArc::ID()) {
+    return FeaturePtr(new SketchPlugin_MacroEllipticArc);
   } else if (theFeatureID == SketchPlugin_SketchDrawer::ID()) {
     return FeaturePtr(new SketchPlugin_SketchDrawer);
   }
@@ -297,6 +303,7 @@ std::shared_ptr<ModelAPI_FeatureStateMessage> SketchPlugin_Plugin
       aMsg->setState(SketchPlugin_Circle::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_Arc::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_Ellipse::ID(), aHasSketchPlane);
+      aMsg->setState(SketchPlugin_EllipticArc::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_Projection::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_ConstraintCoincidence::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_ConstraintCoincidenceInternal::ID(), aHasSketchPlane);
@@ -322,6 +329,7 @@ std::shared_ptr<ModelAPI_FeatureStateMessage> SketchPlugin_Plugin
       aMsg->setState(SketchPlugin_MacroArc::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_MacroCircle::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_MacroEllipse::ID(), aHasSketchPlane);
+      aMsg->setState(SketchPlugin_MacroEllipticArc::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_ConstraintDistanceHorizontal::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_ConstraintDistanceVertical::ID(), aHasSketchPlane);
       // SketchRectangle is a python feature, so its ID is passed just as a string
index 4f55be24d485ffb1d9997890f99f5da42e708fcd..472078f18b4dea3aaf274237f2b12430f813afb7 100644 (file)
 #include "SketchPlugin_Tools.h"
 
 #include "SketchPlugin_ConstraintCoincidence.h"
+#include "SketchPlugin_ConstraintCoincidenceInternal.h"
 #include "SketchPlugin_ConstraintLength.h"
 #include "SketchPlugin_ConstraintTangent.h"
+#include "SketchPlugin_Ellipse.h"
 #include "SketchPlugin_Line.h"
 #include "SketchPlugin_Point.h"
 #include "SketchPlugin_SketchEntity.h"
@@ -429,6 +431,68 @@ FeaturePtr createConstraintObjectObject(SketchPlugin_Sketch* theSketch,
   return aConstraint;
 }
 
+void createAuxiliaryPointOnEllipse(const FeaturePtr& theEllipseFeature,
+                                   const std::string& theEllipsePoint)
+{
+  SketchPlugin_Sketch* aSketch =
+      std::dynamic_pointer_cast<SketchPlugin_Feature>(theEllipseFeature)->sketch();
+
+  FeaturePtr aPointFeature = aSketch->addFeature(SketchPlugin_Point::ID());
+  aPointFeature->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(true);
+  aPointFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theEllipseFeature);
+
+  AttributePoint2DPtr anElPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+    theEllipseFeature->attribute(theEllipsePoint));
+
+  AttributePoint2DPtr aCoord = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+    aPointFeature->attribute(SketchPlugin_Point::COORD_ID()));
+  aCoord->setValue(anElPoint->x(), anElPoint->y());
+
+  aPointFeature->execute();
+  std::string aName = theEllipseFeature->name() + "_" + theEllipsePoint;
+  aPointFeature->data()->setName(aName);
+  aPointFeature->lastResult()->data()->setName(aName);
+
+  createConstraintAttrAttr(aSketch,
+      SketchPlugin_ConstraintCoincidenceInternal::ID(), anElPoint, aCoord);
+}
+
+void createAuxiliaryAxisOfEllipse(const FeaturePtr& theEllipseFeature,
+                                  const std::string& theStartPoint,
+                                  const std::string& theEndPoint)
+{
+  SketchPlugin_Sketch* aSketch =
+      std::dynamic_pointer_cast<SketchPlugin_Feature>(theEllipseFeature)->sketch();
+
+  FeaturePtr aLineFeature = aSketch->addFeature(SketchPlugin_Line::ID());
+  aLineFeature->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(true);
+  aLineFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theEllipseFeature);
+
+  AttributePoint2DPtr aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+    theEllipseFeature->attribute(theStartPoint));
+  AttributePoint2DPtr aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+    theEllipseFeature->attribute(theEndPoint));
+
+  AttributePoint2DPtr aLineStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+    aLineFeature->attribute(SketchPlugin_Line::START_ID()));
+  aLineStart->setValue(aStartPoint->x(), aStartPoint->y());
+
+  AttributePoint2DPtr aLineEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+    aLineFeature->attribute(SketchPlugin_Line::END_ID()));
+  aLineEnd->setValue(aEndPoint->x(), aEndPoint->y());
+
+  aLineFeature->execute();
+  std::string aName = theEllipseFeature->name() + "_" +
+    (theStartPoint == SketchPlugin_Ellipse::MAJOR_AXIS_START_ID() ? "major_axis" : "minor_axis");
+  aLineFeature->data()->setName(aName);
+  aLineFeature->lastResult()->data()->setName(aName);
+
+  createConstraintAttrAttr(aSketch,
+      SketchPlugin_ConstraintCoincidenceInternal::ID(), aStartPoint, aLineStart);
+  createConstraintAttrAttr(aSketch,
+      SketchPlugin_ConstraintCoincidenceInternal::ID(), aEndPoint, aLineEnd);
+}
+
 GeomPnt2dPtr flyoutPointCoordinates(const ConstraintPtr& theConstraint)
 {
   // currently process Length constraints only
index 730d865b9127c4c9eee76c2995c18a862cd4bc01..31162f91de25c9089dc021840634fa9873ba7ff8 100644 (file)
@@ -103,6 +103,21 @@ void createCoincidenceOrTangency(SketchPlugin_Feature* theFeature,
                                  const ObjectPtr theObject,
                                  const bool theIsCanBeTangent);
 
+/// Creates auxiliary point for ellipse and corresponding internal constraint.
+/// \param[in] theEllipse   base ellipse feature
+/// \param[in] theAttrName  name of the attribute of the ellipse,
+///                         the new point should be constrained
+void createAuxiliaryPointOnEllipse(const FeaturePtr& theEllipseFeature,
+                                   const std::string& theAttrName);
+
+/// Creates auxiliary axis for ellipse and corresponding internal constraints.
+/// \param[in] theEllipse   base ellipse feature
+/// \param[in] theStartAttr name of the attribute of the ellipse, the line is started
+/// \param[in] theEndAttr   name of the attribute of the ellipse, the line is ended
+void createAuxiliaryAxisOfEllipse(const FeaturePtr& theEllipseFeature,
+                                  const std::string& theStartAttr,
+                                  const std::string& theEndAttr);
+
 /// Creates passing point or tangent curve basing on the given attributes are initialized.
 /// \param[in]  theRefAttr       prefered attribute to be converted
 /// \param[in]  theDefaultAttr   default attribute if theRefAttr is not initialized
index 63ab98c89e98623e622fd2d6b58ec6f28026e186..a889f1068cf658ccc4a8248a981a90efefcddbaf 100644 (file)
@@ -1150,7 +1150,7 @@ bool SketchPlugin_ProjectionValidator::isValid(const AttributePtr& theAttribute,
     return aValid;
   }
 
-  theError = "Error: Selected object is not line, circle or arc.";
+  theError = "Error: Selected object is not supported for projection.";
   return false;
 }
 
index 8b1c3db3113d2535d1d2ea9632cbc7c6e3df93e0..fe1f4e2a1204f00a4229b3478a6831b1c71b9241 100644 (file)
@@ -5,7 +5,7 @@
         id="Sketch"
         nested="SketchPoint SketchIntersectionPoint SketchLine
                 SketchCircle SketchMacroCircle SketchArc SketchMacroArc
-                SketchEllipse SketchMacroEllipse
+                SketchEllipse SketchMacroEllipse SketchEllipticArc SketchMacroEllipticArc
                 SketchRectangle
                 SketchProjection
                 SketchConstraintLength SketchConstraintRadius SketchConstraintDistance SketchConstraintDistanceHorizontal SketchConstraintDistanceVertical
@@ -51,7 +51,7 @@
         <validator id="GeomValidators_Different" parameters="StartPoint,EndPoint"/>
       </feature>
     </group>
-    <group id="Circular geometry">
+    <group id="Conical geometry">
       <!-- SketchCircle is a hidden feature. It is created inside SketchMacroCircle. -->
       <feature id="SketchCircle"
                title="Circle"
         </sketch_shape_selector>
         <!--<validator id="PartSet_FilletSelection"/>-->
       </feature>
-      <!--  SketchSplit  -->
-      <feature id="SketchSplit" title="Split"
-               tooltip="Cut selected segment arc or circle on existing coincident points"
-               icon="icons/Sketch/split.png"
-               helpfile="splitFeature.html">
-        <sketch_feature_point_selector
-            id="SelectedObject"
-            selection_attributes="SelectedObject SelectedPoint PreviewObject PreviewPoint"
-            label="Segment"
-            tooltip="Select segment for split"
-            shape_types="edge"
-            use_external="false">
-          <validator id="SketchPlugin_SplitValidator"/>
-        </sketch_feature_point_selector>
-        <validator id="PartSet_SplitSelection"/>
-      </feature>
-      <!--  SketchTrim  -->
-      <feature id="SketchTrim" title="Trim"
-               tooltip="Trim selected segment arc or circle on intersection points nearest to the graphic selection"
-               icon="icons/Sketch/trim.png"
-               helpfile="trimFeature.html">
-        <sketch_feature_point_selector
-            id="SelectedObject"
-            selection_attributes="SelectedObject SelectedPoint PreviewObject PreviewPoint"
-            label="Segment"
-            tooltip="Select segment for trim"
-            shape_types="edge"
-            use_external="false">
-          <validator id="SketchPlugin_TrimValidator"/>
-        </sketch_feature_point_selector>
-        <validator id="PartSet_SplitSelection"/>
-      </feature>
-    </group>
 
-    <group id="Elliptic geometry">
       <!-- SketchEllipse is a hidden feature. It is created inside SketchMacroEllipse. -->
       <feature id="SketchEllipse"
                title="Ellipse"
                                      title="Passed point"
                                      tooltip="Passed point coordinates"
                                      accept_expressions="0"
-                                     enable_value="enable_by_preferences">
-              <!--          <validator id="SketchPlugin_CirclePassedPointValidator"/> -->
-            </sketch-2dpoint_selector>
+                                     enable_value="enable_by_preferences"/>
           </box>
           <box id="by_major_axis_and_point"
                icon="icons/Sketch/ellipse_axes_32x32.png"
                                      enable_value="enable_by_preferences"/>
           </box>
         </toolbox>
-<!--        <validator id="GeomValidators_Different" parameters="center_point_ref,passed_point_ref"/> -->
         <labelvalue id="major_radius"
                     icon="icons/Sketch/radius_major.png"
                     label="Major radius"
                    default="false"
                    obligatory="0"/>
       </feature>
+
+      <!-- SketchEllipticArc is a hidden feature. It is created inside SketchMacroEllipse. -->
+      <feature id="SketchEllipticArc"
+               title="Elliptic Arc"
+               tooltip="Create elliptic arc"
+               icon="icons/Sketch/elliptic_arc.png"
+               internal="1">
+        <sketch-2dpoint_selector id="ellipse_center"
+                                 title="Center"
+                                 tooltip="Center coordinates"
+                                 accept_expressions="0"
+                                 enable_value="enable_by_preferences"/>
+        <sketch-2dpoint_selector id="ellipse_first_focus"
+                                 title="First focus"
+                                 tooltip="Focus coordinates"
+                                 accept_expressions="0"
+                                 enable_value="enable_by_preferences"/>
+        <sketch-2dpoint_selector id="ellipse_second_focus"
+                                 title="Second focus"
+                                 tooltip="Focus coordinates"
+                                 accept_expressions="0"
+                                 enable_value="enable_by_preferences"/>
+        <sketch-2dpoint_selector id="ellipse_major_axis_start_point"
+                                 title="Major axis start"
+                                 tooltip="Coordinates of point on negative direction of major axis"
+                                 accept_expressions="0"
+                                 enable_value="enable_by_preferences"/>
+        <sketch-2dpoint_selector id="ellipse_major_axis_end_point"
+                                 title="Major axis end"
+                                 tooltip="Coordinates of point on positive direction of major axis"
+                                 accept_expressions="0"
+                                 enable_value="enable_by_preferences"/>
+        <sketch-2dpoint_selector id="ellipse_minor_axis_start_point"
+                                 title="Minor axis start"
+                                 tooltip="Coordinates of point on negative direction of minor axis"
+                                 accept_expressions="0"
+                                 enable_value="enable_by_preferences"/>
+        <sketch-2dpoint_selector id="ellipse_minor_axis_end_point"
+                                 title="Minor axis end"
+                                 tooltip="Coordinates of point on positive direction of minor axis"
+                                 accept_expressions="0"
+                                 enable_value="enable_by_preferences"/>
+        <sketch-2dpoint_selector id="start_point"
+                                 title="Start point"
+                                 tooltip="Arc start point coordinates"
+                                 accept_expressions="0"
+                                 enable_value="enable_by_preferences"/>
+        <sketch-2dpoint_selector id="end_point"
+                                 title="End point"
+                                 tooltip="Arc end point coordinates"
+                                 accept_expressions="0"
+                                 enable_value="enable_by_preferences"/>
+        <labelvalue id="ellipse_major_radius"
+                    icon="icons/Sketch/radius_major.png"
+                    label="Major radius"
+                    tooltip="Set major radius"
+                    default="computed"
+                    accept_expressions="0"
+                    enable_value="enable_by_preferences">
+        </labelvalue>
+        <labelvalue id="ellipse_minor_radius"
+                    icon="icons/Sketch/radius_minor.png"
+                    label="Minor radius"
+                    tooltip="Set minor radius"
+                    default="computed"
+                    accept_expressions="0"
+                    enable_value="enable_by_preferences">
+        </labelvalue>
+        <boolvalue id="Auxiliary" label="Auxiliary" default="false" tooltip="Construction element" obligatory="0"/>
+      </feature>
+      <!-- SketchMacroEllipticArc -->
+      <feature id="SketchMacroEllipticArc"
+               icon="icons/Sketch/elliptic_arc.png"
+               title="Elliptical arc"
+               tooltip="Create elliptical arc"
+               helpfile="ellipseFeature.html">
+        <sketch-2dpoint_selector id="center"
+                                 reference_attribute="center_ref"
+                                 title="Center point"
+                                 tooltip="Center point coordinates"
+                                 accept_expressions="0"
+                                 enable_value="enable_by_preferences"/>
+        <sketch-2dpoint_selector id="major_axis_point"
+                                 reference_attribute="major_axis_point_ref"
+                                 title="Major axis point"
+                                 tooltip="Major axis point coordinates"
+                                 accept_expressions="0"
+                                 enable_value="enable_by_preferences"/>
+        <sketch-2dpoint_selector id="start_point"
+                                 reference_attribute="start_point_ref"
+                                 title="Start point"
+                                 tooltip="Arc start point coordinates"
+                                 accept_expressions="0"
+                                 enable_value="enable_by_preferences"/>
+        <sketch-2dpoint_selector id="end_point"
+                                 reference_attribute="end_point_ref"
+                                 title="End point"
+                                 tooltip="Arc end point coordinates"
+                                 accept_expressions="0"
+                                 enable_value="enable_by_preferences"/>
+        <labelvalue id="major_radius"
+                    icon="icons/Sketch/radius_major.png"
+                    label="Major radius"
+                    tooltip="Set major radius"
+                    default="computed"
+                    accept_expressions="0"
+                    obligatory="0"
+                    enable_value="enable_by_preferences">
+          <validator id="GeomValidators_Positive"/>
+        </labelvalue>
+        <labelvalue id="minor_radius"
+                    icon="icons/Sketch/radius_minor.png"
+                    label="Minor radius"
+                    tooltip="Set minor radius"
+                    default="computed"
+                    accept_expressions="0"
+                    obligatory="0"
+                    enable_value="enable_by_preferences">
+          <validator id="GeomValidators_Positive"/>
+        </labelvalue>
+        <boolvalue id="Auxiliary"
+                   tooltip="Construction element"
+                   label="Auxiliary"
+                   default="false"
+                   obligatory="0"/>
+      </feature>
+    </group>
+
+    <group id="Segmentation">
+      <!--  SketchSplit  -->
+      <feature id="SketchSplit" title="Split"
+               tooltip="Cut selected segment arc or circle on existing coincident points"
+               icon="icons/Sketch/split.png"
+               helpfile="splitFeature.html">
+        <sketch_feature_point_selector
+            id="SelectedObject"
+            selection_attributes="SelectedObject SelectedPoint PreviewObject PreviewPoint"
+            label="Segment"
+            tooltip="Select segment for split"
+            shape_types="edge"
+            use_external="false">
+          <validator id="SketchPlugin_SplitValidator"/>
+        </sketch_feature_point_selector>
+        <validator id="PartSet_SplitSelection"/>
+      </feature>
+      <!--  SketchTrim  -->
+      <feature id="SketchTrim" title="Trim"
+               tooltip="Trim selected segment arc or circle on intersection points nearest to the graphic selection"
+               icon="icons/Sketch/trim.png"
+               helpfile="trimFeature.html">
+        <sketch_feature_point_selector
+            id="SelectedObject"
+            selection_attributes="SelectedObject SelectedPoint PreviewObject PreviewPoint"
+            label="Segment"
+            tooltip="Select segment for trim"
+            shape_types="edge"
+            use_external="false">
+          <validator id="SketchPlugin_TrimValidator"/>
+        </sketch_feature_point_selector>
+        <validator id="PartSet_SplitSelection"/>
+      </feature>
     </group>
 
     <group id="Projection">
index bb8af7873db682ede8da9d82bf456dce45599a9c..3a7aa0cb420dbba3d96e996e16a71dca50cf0fc2 100644 (file)
 #include <PlaneGCSSolver_EdgeWrapper.h>
 #include <cmath>
 
+static bool isLine(const GCSCurvePtr& theEntity)
+{
+  return std::dynamic_pointer_cast<GCS::Line>(theEntity).get();
+}
+
+static bool isCircle(const GCSCurvePtr& theEntity)
+{
+  return std::dynamic_pointer_cast<GCS::Circle>(theEntity).get();
+}
+
+static bool isArc(const GCSCurvePtr& theEntity)
+{
+  return std::dynamic_pointer_cast<GCS::Arc>(theEntity).get();
+}
+
+static bool isEllipse(const GCSCurvePtr& theEntity)
+{
+  return std::dynamic_pointer_cast<GCS::Ellipse>(theEntity).get();
+}
+
+static bool isEllipticArc(const GCSCurvePtr& theEntity)
+{
+  return std::dynamic_pointer_cast<GCS::ArcOfEllipse>(theEntity).get();
+}
+
+
 PlaneGCSSolver_EdgeWrapper::PlaneGCSSolver_EdgeWrapper(const GCSCurvePtr theEntity)
   : myEntity(theEntity)
 {
-  std::shared_ptr<GCS::Line> aLine = std::dynamic_pointer_cast<GCS::Line>(myEntity);
-  if (aLine) myType = ENTITY_LINE;
-  else {
-    std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(myEntity);
-    if (anArc) myType = ENTITY_ARC;
-    else {
-      std::shared_ptr<GCS::Circle> aCircle = std::dynamic_pointer_cast<GCS::Circle>(myEntity);
-      if (aCircle) myType = ENTITY_CIRCLE;
-      else {
-        std::shared_ptr<GCS::Ellipse> anEllipse =
-            std::dynamic_pointer_cast<GCS::Ellipse>(myEntity);
-        if (anEllipse) myType = ENTITY_ELLIPSE;
-      }
-    }
-  }
+  if (isLine(myEntity))
+    myType = ENTITY_LINE;
+  else if (isArc(myEntity))
+    myType = ENTITY_ARC;
+  else if (isCircle(myEntity))
+    myType = ENTITY_CIRCLE;
+  else if (isEllipticArc(myEntity))
+    myType = ENTITY_ELLIPTICAL_ARC;
+  else if (isEllipse(myEntity))
+    myType = ENTITY_ELLIPSE;
 }
 
 static double squareDistance(const GCS::Point& theP1, const GCS::Point& theP2)
@@ -49,27 +70,36 @@ static double squareDistance(const GCS::Point& theP1, const GCS::Point& theP2)
 
 bool PlaneGCSSolver_EdgeWrapper::isDegenerated() const
 {
-  static const double aSqTol = tolerance * 1e-2;
-  static const double aMaxRadius = 1e8;
+  static const double THE_SQ_TOL = tolerance * 1e-2;
+  static const double THE_ANGLE_TOL = 1.e-5;
+  static const double THE_MAX_RADIUS = 1e8;
+  static const double THE_SQ_MAX_RADIUS = THE_MAX_RADIUS * THE_MAX_RADIUS;
+
   if (myType == ENTITY_LINE) {
     std::shared_ptr<GCS::Line> aLine = std::dynamic_pointer_cast<GCS::Line>(myEntity);
-    return squareDistance(aLine->p1, aLine->p2) < aSqTol;
+    return squareDistance(aLine->p1, aLine->p2) < THE_SQ_TOL;
   }
   else if (myType == ENTITY_CIRCLE) {
     std::shared_ptr<GCS::Circle> aCircle = std::dynamic_pointer_cast<GCS::Circle>(myEntity);
-    return *aCircle->rad < tolerance || *aCircle->rad > aMaxRadius;
+    return *aCircle->rad < tolerance || *aCircle->rad > THE_MAX_RADIUS;
   }
   else if (myType == ENTITY_ARC) {
-    static const double anAngleTol = 1.e-5;
     std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(myEntity);
     double anAngleDiff = fabs(*anArc->startAngle - *anArc->endAngle);
     double aSqRadius = squareDistance(anArc->center, anArc->start);
-    return aSqRadius < aSqTol || aSqRadius > aMaxRadius * aMaxRadius || // <- arc radius
-           anAngleDiff < anAngleTol || fabs(anAngleDiff - 2*PI) < anAngleTol; // <- arc angle
+    return aSqRadius < THE_SQ_TOL || aSqRadius > THE_SQ_MAX_RADIUS || // <- arc radius
+           anAngleDiff < THE_ANGLE_TOL || fabs(anAngleDiff - 2*PI) < THE_ANGLE_TOL; // <- arc angle
   }
   else if (myType == ENTITY_ELLIPSE) {
     std::shared_ptr<GCS::Ellipse> anEllipse = std::dynamic_pointer_cast<GCS::Ellipse>(myEntity);
-    return *anEllipse->radmin < tolerance;
+    return *anEllipse->radmin < tolerance || anEllipse->getRadMaj() > THE_MAX_RADIUS;
+  }
+  else if (myType == ENTITY_ELLIPTICAL_ARC) {
+    std::shared_ptr<GCS::ArcOfEllipse> anArc =
+        std::dynamic_pointer_cast<GCS::ArcOfEllipse>(myEntity);
+    double anAngleDiff = fabs(*anArc->startAngle - *anArc->endAngle);
+    return *anArc->radmin < THE_SQ_TOL || anArc->getRadMaj() > THE_SQ_MAX_RADIUS || // <- arc radius
+           anAngleDiff < THE_ANGLE_TOL || fabs(anAngleDiff - 2*PI) < THE_ANGLE_TOL; // <- arc angle
   }
   return false;
 }
index 4755eb6bfd449e0b7ae74efa8a9e23cbb6f02129..400319aed4bd9804a46ec5c2c118da1d8473c9d7 100644 (file)
 #include <PlaneGCSSolver_PointWrapper.h>
 #include <PlaneGCSSolver_ScalarWrapper.h>
 #include <PlaneGCSSolver_BooleanWrapper.h>
+#include <PlaneGCSSolver_Tools.h>
 
 #include <SketchPlugin_Arc.h>
 #include <SketchPlugin_Circle.h>
 #include <SketchPlugin_Ellipse.h>
+#include <SketchPlugin_EllipticArc.h>
 #include <SketchPlugin_IntersectionPoint.h>
 #include <SketchPlugin_Line.h>
 #include <SketchPlugin_Point.h>
@@ -42,6 +44,8 @@ static EntityWrapperPtr createCircle(const AttributeEntityMap& theAttributes);
 static EntityWrapperPtr createArc(const AttributeEntityMap&    theAttributes,
                                   PlaneGCSSolver_Storage*      theStorage);
 static EntityWrapperPtr createEllipse(const AttributeEntityMap& theAttributes);
+static EntityWrapperPtr createEllipticArc(const AttributeEntityMap& theAttributes,
+                                          PlaneGCSSolver_Storage*   theStorage);
 
 
 PlaneGCSSolver_FeatureBuilder::PlaneGCSSolver_FeatureBuilder(
@@ -95,6 +99,9 @@ EntityWrapperPtr PlaneGCSSolver_FeatureBuilder::createFeature(FeaturePtr theFeat
   // Ellipse
   else if (aFeatureKind == SketchPlugin_Ellipse::ID())
     aResult = createEllipse(myAttributes);
+  // Arc of ellipse
+  else if (aFeatureKind == SketchPlugin_EllipticArc::ID())
+    aResult = createEllipticArc(myAttributes, myStorage);
   // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
   else if (aFeatureKind == SketchPlugin_Point::ID() ||
            aFeatureKind == SketchPlugin_IntersectionPoint::ID()) {
@@ -189,29 +196,16 @@ EntityWrapperPtr createArc(const AttributeEntityMap&    theAttributes,
     }
   }
 
-  // Additional atrtributes of arc necessary for PlaneGCS solver
+  // Additional attributes of arc necessary for PlaneGCS solver
   // (start and end angles, radius)
   aNewArc->startAngle = createParameter(theStorage);
   aNewArc->endAngle   = createParameter(theStorage);
   aNewArc->rad        = createParameter(theStorage);
 
-  static std::shared_ptr<GeomAPI_Dir2d> OX(new GeomAPI_Dir2d(1.0, 0.0));
-  std::shared_ptr<GeomAPI_Pnt2d> aCenter(
-      new GeomAPI_Pnt2d(*aNewArc->center.x, *aNewArc->center.y));
-  std::shared_ptr<GeomAPI_Pnt2d> aStart(
-      new GeomAPI_Pnt2d(*aNewArc->start.x, *aNewArc->start.y));
-
-  *aNewArc->rad = aStart->distance(aCenter);
-
-  std::shared_ptr<GeomAPI_Dir2d> aDir(new GeomAPI_Dir2d(aStart->xy()->decreased(aCenter->xy())));
-  *aNewArc->startAngle = OX->angle(aDir);
-
-  aDir = std::shared_ptr<GeomAPI_Dir2d>(
-      new GeomAPI_Dir2d((*aNewArc->end.x) - aCenter->x(), (*aNewArc->end.y) - aCenter->y()));
-  *aNewArc->endAngle = OX->angle(aDir);
-
   EdgeWrapperPtr anArcWrapper(new PlaneGCSSolver_EdgeWrapper(aNewArc));
   anArcWrapper->setReversed(isReversed);
+  PlaneGCSSolver_Tools::recalculateArcParameters(anArcWrapper);
+
   return anArcWrapper;
 }
 
@@ -247,6 +241,53 @@ EntityWrapperPtr createEllipse(const AttributeEntityMap& theAttributes)
   return anEllipseWrapper;
 }
 
+EntityWrapperPtr createEllipticArc(const AttributeEntityMap& theAttributes,
+                                   PlaneGCSSolver_Storage*   theStorage)
+{
+  std::shared_ptr<GCS::ArcOfEllipse> aNewArc(new GCS::ArcOfEllipse);
+
+  BooleanWrapperPtr isReversed;
+  std::map<std::string, EntityWrapperPtr> anAdditionalAttributes;
+
+  AttributeEntityMap::const_iterator anIt = theAttributes.begin();
+  for (; anIt != theAttributes.end(); ++anIt) {
+    std::shared_ptr<PlaneGCSSolver_PointWrapper> aPoint =
+        std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(anIt->second);
+    if (aPoint) {
+      if (anIt->first->id() == SketchPlugin_EllipticArc::CENTER_ID())
+        aNewArc->center = *(aPoint->point());
+      else if (anIt->first->id() == SketchPlugin_EllipticArc::FIRST_FOCUS_ID())
+        aNewArc->focus1 = *(aPoint->point());
+      else if (anIt->first->id() == SketchPlugin_EllipticArc::START_POINT_ID())
+        aNewArc->start = *(aPoint->point());
+      else if (anIt->first->id() == SketchPlugin_EllipticArc::END_POINT_ID())
+        aNewArc->end = *(aPoint->point());
+      else
+        anAdditionalAttributes[anIt->first->id()] = anIt->second;
+    }
+    else if (anIt->first->id() == SketchPlugin_EllipticArc::MINOR_RADIUS_ID()) {
+      ScalarWrapperPtr aScalar =
+          std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(anIt->second);
+      aNewArc->radmin = aScalar->scalar();
+    }
+    else if (anIt->first->id() == SketchPlugin_EllipticArc::REVERSED_ID())
+      isReversed = std::dynamic_pointer_cast<PlaneGCSSolver_BooleanWrapper>(anIt->second);
+    else
+      anAdditionalAttributes[anIt->first->id()] = anIt->second;
+  }
+
+  // Additional attributes of elliptic arc necessary for PlaneGCS solver (start and end angles)
+  aNewArc->startAngle = createParameter(theStorage);
+  aNewArc->endAngle = createParameter(theStorage);
+
+  EdgeWrapperPtr anEllipseWrapper(new PlaneGCSSolver_EdgeWrapper(aNewArc));
+  anEllipseWrapper->setReversed(isReversed);
+  anEllipseWrapper->setAdditionalAttributes(anAdditionalAttributes);
+  PlaneGCSSolver_Tools::recalculateArcParameters(anEllipseWrapper);
+
+  return anEllipseWrapper;
+}
+
 bool isAttributeApplicable(const std::string& theAttrName, const std::string& theOwnerName)
 {
   if (theOwnerName == SketchPlugin_Arc::ID()) {
@@ -274,6 +315,20 @@ bool isAttributeApplicable(const std::string& theAttrName, const std::string& th
            theAttrName == SketchPlugin_Ellipse::MAJOR_RADIUS_ID() ||
            theAttrName == SketchPlugin_Ellipse::MINOR_RADIUS_ID();
   }
+  else if (theOwnerName == SketchPlugin_EllipticArc::ID()) {
+    return theAttrName == SketchPlugin_EllipticArc::CENTER_ID() ||
+           theAttrName == SketchPlugin_EllipticArc::FIRST_FOCUS_ID() ||
+           theAttrName == SketchPlugin_EllipticArc::SECOND_FOCUS_ID() ||
+           theAttrName == SketchPlugin_EllipticArc::MAJOR_AXIS_START_ID() ||
+           theAttrName == SketchPlugin_EllipticArc::MAJOR_AXIS_END_ID() ||
+           theAttrName == SketchPlugin_EllipticArc::MINOR_AXIS_START_ID() ||
+           theAttrName == SketchPlugin_EllipticArc::MINOR_AXIS_END_ID() ||
+           theAttrName == SketchPlugin_EllipticArc::MAJOR_RADIUS_ID() ||
+           theAttrName == SketchPlugin_EllipticArc::MINOR_RADIUS_ID() ||
+           theAttrName == SketchPlugin_EllipticArc::START_POINT_ID() ||
+           theAttrName == SketchPlugin_EllipticArc::END_POINT_ID() ||
+           theAttrName == SketchPlugin_EllipticArc::REVERSED_ID();
+  }
 
   // suppose that all remaining features are points
   return theAttrName == SketchPlugin_Point::COORD_ID();
index 6a41efc0d85c2b4daa6efd9f12bf647b61696d2a..2aff74fb48d75062aa6140be07144d1554ff2181 100644 (file)
@@ -224,28 +224,8 @@ bool PlaneGCSSolver_Storage::update(FeaturePtr theFeature, bool theForce)
     notify(theFeature);
 
   // update arc
-  if (aRelated && aRelated->type() == ENTITY_ARC) {
-    /// TODO: this code should be shared with FeatureBuilder somehow
-
-    std::shared_ptr<PlaneGCSSolver_EdgeWrapper> anEntity =
-      std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(aRelated);
-    std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anEntity->entity());
-
-    static std::shared_ptr<GeomAPI_Dir2d> OX(new GeomAPI_Dir2d(1.0, 0.0));
-    std::shared_ptr<GeomAPI_Pnt2d> aCenter(
-      new GeomAPI_Pnt2d(*anArc->center.x, *anArc->center.y));
-    std::shared_ptr<GeomAPI_Pnt2d> aStart(
-      new GeomAPI_Pnt2d(*anArc->start.x, *anArc->start.y));
-
-    *anArc->rad = aStart->distance(aCenter);
-
-    std::shared_ptr<GeomAPI_Dir2d> aDir(new GeomAPI_Dir2d(aStart->xy()->decreased(aCenter->xy())));
-    *anArc->startAngle = OX->angle(aDir);
-
-    aDir = std::shared_ptr<GeomAPI_Dir2d>(
-      new GeomAPI_Dir2d((*anArc->end.x) - aCenter->x(), (*anArc->end.y) - aCenter->y()));
-    *anArc->endAngle = OX->angle(aDir);
-  }
+  if (aRelated)
+    PlaneGCSSolver_Tools::recalculateArcParameters(aRelated);
 
   return isUpdated;
 }
@@ -397,11 +377,42 @@ static void createEllipseConstraints(
   ConstraintWrapperPtr aWrapper(
     new PlaneGCSSolver_ConstraintWrapper(anEllipseConstraints, CONSTRAINT_UNKNOWN));
   aWrapper->setId(theConstraintID);
-  constraintsToSolver(aWrapper, theSolver);
+  if (theSolver)
+    constraintsToSolver(aWrapper, theSolver);
 
   theConstraints[theEllipse] = aWrapper;
 }
 
+static void createEllipticArcConstraints(
+    const EntityWrapperPtr& theEllipticArc,
+    const SolverPtr& theSolver,
+    const ConstraintID theConstraintID,
+    std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
+{
+  // create base constraints for the ellipse without adding them to solver
+  createEllipseConstraints(theEllipticArc, SolverPtr(), theConstraintID, theConstraints);
+
+  ConstraintWrapperPtr& aConstraint = theConstraints[theEllipticArc];
+  std::list<GCSConstraintPtr> anEllArcConstraints = aConstraint->constraints();
+
+  // constrain extremities of the elliptic arc
+  EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theEllipticArc);
+  std::shared_ptr<GCS::ArcOfEllipse> anArc =
+      std::dynamic_pointer_cast<GCS::ArcOfEllipse>(anEdge->entity());
+
+  anEllArcConstraints.push_back(GCSConstraintPtr(
+      new GCS::ConstraintCurveValue(anArc->start, anArc->start.x, *anArc, anArc->startAngle)));
+  anEllArcConstraints.push_back(GCSConstraintPtr(
+      new GCS::ConstraintCurveValue(anArc->start, anArc->start.y, *anArc, anArc->startAngle)));
+  anEllArcConstraints.push_back(GCSConstraintPtr(
+      new GCS::ConstraintCurveValue(anArc->end, anArc->end.x, *anArc, anArc->endAngle)));
+  anEllArcConstraints.push_back(GCSConstraintPtr(
+      new GCS::ConstraintCurveValue(anArc->end, anArc->end.y, *anArc, anArc->endAngle)));
+
+  aConstraint->setConstraints(anEllArcConstraints);
+  constraintsToSolver(aConstraint, theSolver);
+}
+
 void PlaneGCSSolver_Storage::createAuxiliaryConstraints(const EntityWrapperPtr& theEntity)
 {
   if (!theEntity || theEntity->isExternal())
@@ -411,6 +422,10 @@ void PlaneGCSSolver_Storage::createAuxiliaryConstraints(const EntityWrapperPtr&
     createArcConstraints(theEntity, mySketchSolver, ++myConstraintLastID, myAuxConstraintMap);
   else if (theEntity->type() == ENTITY_ELLIPSE)
     createEllipseConstraints(theEntity, mySketchSolver, ++myConstraintLastID, myAuxConstraintMap);
+  else if (theEntity->type() == ENTITY_ELLIPTICAL_ARC) {
+    createEllipticArcConstraints(theEntity, mySketchSolver,
+                                 ++myConstraintLastID, myAuxConstraintMap);
+  }
 }
 
 void PlaneGCSSolver_Storage::removeAuxiliaryConstraints(const EntityWrapperPtr& theEntity)
@@ -423,30 +438,42 @@ void PlaneGCSSolver_Storage::removeAuxiliaryConstraints(const EntityWrapperPtr&
   }
 }
 
+template <typename ARCTYPE>
+void adjustArcParametrization(ARCTYPE& theArc, bool theReversed)
+{
+  // tune start angle of the arc to be in [0, 2PI]
+  while (*theArc.startAngle < -PI)
+    *theArc.startAngle += 2.0 * PI;
+  while (*theArc.startAngle >= PI)
+    *theArc.startAngle -= 2.0 * PI;
+  // adjust end angle of the arc
+  if (theReversed) {
+    while (*theArc.endAngle > *theArc.startAngle)
+      *theArc.endAngle -= 2.0 * PI;
+    while (*theArc.endAngle + 2 * PI < *theArc.startAngle)
+      *theArc.endAngle += 2.0 * PI;
+  }
+  else {
+    while (*theArc.endAngle < *theArc.startAngle)
+      *theArc.endAngle += 2.0 * PI;
+    while (*theArc.endAngle > *theArc.startAngle + 2 * PI)
+      *theArc.endAngle -= 2.0 * PI;
+  }
+}
+
 void PlaneGCSSolver_Storage::adjustParametrizationOfArcs()
 {
   std::map<EntityWrapperPtr, ConstraintWrapperPtr>::iterator anIt = myAuxConstraintMap.begin();
   for (; anIt != myAuxConstraintMap.end(); ++anIt) {
     EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(anIt->first);
     std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anEdge->entity());
-    if (!anArc)
-      continue;
-    // tune start angle of the arc to be in [0, 2PI]
-    while (*anArc->startAngle < -PI)
-      *anArc->startAngle += 2.0 * PI;
-    while (*anArc->startAngle >= PI)
-      *anArc->startAngle -= 2.0 * PI;
-    // adjust end angle of the arc
-    if (anEdge->isReversed()) {
-      while (*anArc->endAngle > *anArc->startAngle)
-        *anArc->endAngle -= 2.0 * PI;
-      while (*anArc->endAngle + 2 * PI < *anArc->startAngle)
-        *anArc->endAngle += 2.0 * PI;
-    } else {
-      while (*anArc->endAngle < *anArc->startAngle)
-        *anArc->endAngle += 2.0 * PI;
-      while (*anArc->endAngle > *anArc->startAngle + 2 * PI)
-        *anArc->endAngle -= 2.0 * PI;
+    if (anArc)
+      adjustArcParametrization(*anArc, anEdge->isReversed());
+    else {
+////      std::shared_ptr<GCS::ArcOfEllipse> aEllArc =
+////          std::dynamic_pointer_cast<GCS::ArcOfEllipse>(anEdge->entity());
+////      if (aEllArc)
+////        adjustArcParametrization(*aEllArc, anEdge->isReversed());
     }
   }
 
index 11c265dd0eed1751bafd9071abe41181595a0b31..461ae688522325a98afd8801335ccc5556fa0b6a 100644 (file)
@@ -122,6 +122,9 @@ static GCS::SET_pD lineParameters(const EdgeWrapperPtr& theLine);
 static GCS::SET_pD circleParameters(const EdgeWrapperPtr& theCircle);
 static GCS::SET_pD arcParameters(const EdgeWrapperPtr& theArc);
 static GCS::SET_pD ellipseParameters(const EdgeWrapperPtr& theEllipse);
+static GCS::SET_pD ellipticArcParameters(const EdgeWrapperPtr& theEllipticArc);
+
+static double distance(const GCS::Point& thePnt1, const GCS::Point& thePnt2);
 
 
 
@@ -321,6 +324,54 @@ std::shared_ptr<GeomAPI_Ellipse2d> PlaneGCSSolver_Tools::ellipse(EntityWrapperPt
       new GeomAPI_Ellipse2d(aCenter, anAxis, anEllipse->getRadMaj(), *anEllipse->radmin));
 }
 
+void PlaneGCSSolver_Tools::recalculateArcParameters(EntityWrapperPtr theArc)
+{
+  std::shared_ptr<PlaneGCSSolver_EdgeWrapper> anEdge =
+      std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theArc);
+  if (!anEdge)
+    return;
+
+  GCS::Point aCenter, aStartPnt, aEndPnt;
+  double *aStartAngle, *aEndAngle;
+  GeomDir2dPtr OX;
+
+  if (anEdge->type() == ENTITY_ARC) {
+    std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anEdge->entity());
+
+    aCenter = anArc->center;
+    aStartPnt = anArc->start;
+    aEndPnt = anArc->end;
+
+    *anArc->rad = distance(aCenter, aStartPnt);
+
+    aStartAngle = anArc->startAngle;
+    aEndAngle = anArc->endAngle;
+
+    OX.reset(new GeomAPI_Dir2d(1.0, 0.0));
+  }
+  else if (anEdge->type() == ENTITY_ELLIPTICAL_ARC) {
+    std::shared_ptr<GCS::ArcOfEllipse> aEllArc =
+        std::dynamic_pointer_cast<GCS::ArcOfEllipse>(anEdge->entity());
+
+    aCenter = aEllArc->center;
+    aStartPnt = aEllArc->start;
+    aEndPnt = aEllArc->end;
+
+    aStartAngle = aEllArc->startAngle;
+    aEndAngle = aEllArc->endAngle;
+
+    OX.reset(new GeomAPI_Dir2d(*aEllArc->focus1.x - *aCenter.x, *aEllArc->focus1.y - *aCenter.y));
+  }
+  else // skip other type of entities
+    return;
+
+  GeomDir2dPtr aDir(new GeomAPI_Dir2d(*aStartPnt.x - *aCenter.x, *aStartPnt.y - *aCenter.y));
+  *aStartAngle = OX->angle(aDir);
+
+  aDir.reset(new GeomAPI_Dir2d(*aEndPnt.x - *aCenter.x, *aEndPnt.y - *aCenter.y));
+  *aEndAngle = OX->angle(aDir);
+}
+
 
 
 GCS::SET_pD PlaneGCSSolver_Tools::parameters(const EntityWrapperPtr& theEntity)
@@ -339,6 +390,8 @@ GCS::SET_pD PlaneGCSSolver_Tools::parameters(const EntityWrapperPtr& theEntity)
     return arcParameters(GCS_EDGE_WRAPPER(theEntity));
   case ENTITY_ELLIPSE:
     return ellipseParameters(GCS_EDGE_WRAPPER(theEntity));
+  case ENTITY_ELLIPTICAL_ARC:
+    return ellipticArcParameters(GCS_EDGE_WRAPPER(theEntity));
   default: break;
   }
   return GCS::SET_pD();
@@ -608,10 +661,7 @@ ConstraintWrapperPtr createConstraintEqual(
     aConstrList.push_back(GCSConstraintPtr(
         new GCS::ConstraintP2PDistance(aLine2->p1, aLine2->p2, theIntermed->scalar())));
     // update value of intermediate parameter
-    double x = *aLine1->p1.x - *aLine1->p2.x;
-    double y = *aLine1->p1.y - *aLine1->p2.y;
-    double aLen = sqrt(x*x + y*y);
-    theIntermed->setValue(aLen);
+    theIntermed->setValue(distance(aLine1->p1, aLine1->p2));
   } else {
     std::shared_ptr<GCS::Circle> aCirc1 =
         std::dynamic_pointer_cast<GCS::Circle>(theEntity1->entity());
@@ -678,17 +728,14 @@ GCS::SET_pD circleParameters(const EdgeWrapperPtr& theCircle)
 
 GCS::SET_pD arcParameters(const EdgeWrapperPtr& theArc)
 {
-  GCS::SET_pD aParams;
+  GCS::SET_pD aParams = circleParameters(theArc);
   std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(theArc->entity());
-  aParams.insert(anArc->center.x);
-  aParams.insert(anArc->center.y);
   aParams.insert(anArc->start.x);
   aParams.insert(anArc->start.y);
   aParams.insert(anArc->end.x);
   aParams.insert(anArc->end.y);
   aParams.insert(anArc->startAngle);
   aParams.insert(anArc->endAngle);
-  aParams.insert(anArc->rad);
   return aParams;
 }
 
@@ -704,3 +751,24 @@ GCS::SET_pD ellipseParameters(const EdgeWrapperPtr& theEllipse)
   aParams.insert(anEllipse->radmin);
   return aParams;
 }
+
+GCS::SET_pD ellipticArcParameters(const EdgeWrapperPtr& theEllipticArc)
+{
+  GCS::SET_pD aParams = ellipseParameters(theEllipticArc);
+  std::shared_ptr<GCS::ArcOfEllipse> anArc =
+      std::dynamic_pointer_cast<GCS::ArcOfEllipse>(theEllipticArc->entity());
+  aParams.insert(anArc->start.x);
+  aParams.insert(anArc->start.y);
+  aParams.insert(anArc->end.x);
+  aParams.insert(anArc->end.y);
+  aParams.insert(anArc->startAngle);
+  aParams.insert(anArc->endAngle);
+  return aParams;
+}
+
+double distance(const GCS::Point& thePnt1, const GCS::Point& thePnt2)
+{
+  double x = *thePnt1.x - *thePnt2.x;
+  double y = *thePnt1.y - *thePnt2.y;
+  return sqrt(x*x + y*y);
+}
index 1eb95be4fcb27370a0ba457e77c4bfff66e32850..a02a9948c77a2302f86a4b7d48176b33f3d3f4ea 100644 (file)
@@ -81,6 +81,11 @@ namespace PlaneGCSSolver_Tools
   /// \return empty pointer if the entity is not a line
   std::shared_ptr<GeomAPI_Lin2d> line(FeaturePtr theFeature);
 
+  /// \brief Update start and end parameters of circular and elliptic arcs
+  ///        respectively to start and end points on the arc.
+  ///        For the circular arc, the radius is calculated too.
+  void recalculateArcParameters(EntityWrapperPtr theArc);
+
   /// brief Return list of parameters for the given entity
   GCS::SET_pD parameters(const EntityWrapperPtr& theEntity);
 };
index 2cb63252265c06075bd09ba2a14edc6c0344314e..7e7c6aab1c27e8b302aa0d82cfcc78b65d5c6f24 100644 (file)
@@ -151,6 +151,18 @@ GCS::VEC_pD toParameters(const EntityWrapperPtr& theEntity)
     aParameters.push_back(anEllipse->radmin);
     break;
     }
+  case ENTITY_ELLIPTICAL_ARC: {
+    std::shared_ptr<GCS::ArcOfEllipse> anEllArc =
+        std::dynamic_pointer_cast<GCS::ArcOfEllipse>(anEntity->entity());
+    aParameters.push_back(anEllArc->center.x);
+    aParameters.push_back(anEllArc->center.y);
+    aParameters.push_back(anEllArc->focus1.x);
+    aParameters.push_back(anEllArc->focus1.y);
+    aParameters.push_back(anEllArc->radmin);
+    aParameters.push_back(anEllArc->startAngle);
+    aParameters.push_back(anEllArc->endAngle);
+    break;
+    }
   default:
     break;
   }
index 1c752f47d6e1945128607ff05e9631935983aa9c..e4a59127b81d81d5abbe68455087dbb11f401a77 100644 (file)
@@ -27,6 +27,7 @@
 #include <SketchPlugin_Arc.h>
 #include <SketchPlugin_Circle.h>
 #include <SketchPlugin_Ellipse.h>
+#include <SketchPlugin_EllipticArc.h>
 #include <SketchPlugin_Line.h>
 #include <SketchPlugin_Point.h>
 
@@ -92,9 +93,11 @@ static bool isSimpleMove(FeaturePtr theMovedFeature, AttributePtr theDraggedPoin
   if (theMovedFeature->getKind() == SketchPlugin_Circle::ID() ||
       theMovedFeature->getKind() == SketchPlugin_Ellipse::ID())
     isSimple = (theDraggedPoint.get() != 0);
-  else if (theMovedFeature->getKind() == SketchPlugin_Arc::ID()) {
+  else if (theMovedFeature->getKind() == SketchPlugin_Arc::ID() ||
+           theMovedFeature->getKind() == SketchPlugin_EllipticArc::ID()) {
     isSimple = (theDraggedPoint.get() != 0 &&
-                theDraggedPoint->id() == SketchPlugin_Arc::CENTER_ID());
+               (theDraggedPoint->id() == SketchPlugin_Arc::CENTER_ID() ||
+                theDraggedPoint->id() == SketchPlugin_EllipticArc::CENTER_ID()));
   }
 #endif
   return isSimple;
@@ -152,12 +155,21 @@ ConstraintWrapperPtr SketchSolver_ConstraintMovement::fixArcExtremity(
       myStorage->entity(myMovedFeature));
   std::shared_ptr<GCS::Arc> anArc =
       std::dynamic_pointer_cast<GCS::Arc>(aCircularEntity->entity());
+  std::shared_ptr<GCS::ArcOfEllipse> anEllArc =
+      std::dynamic_pointer_cast<GCS::ArcOfEllipse>(aCircularEntity->entity());
 
   PointWrapperPtr aPoint =
       std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theArcExtremity);
 
-  double* aParams[nbParams] = { aPoint->point()->x, aPoint->point()->y,
-                                anArc->center.x, anArc->center.y };
+  double* aParams[nbParams] = { aPoint->point()->x, aPoint->point()->y, 0, 0 };
+  if (anArc) {
+    aParams[2] = anArc->center.x;
+    aParams[3] = anArc->center.y;
+  }
+  else if (anEllArc) {
+    aParams[2] = anEllArc->center.x;
+    aParams[3] = anEllArc->center.y;
+  }
 
   std::list<GCSConstraintPtr> aConstraints;
   for (int i = 0; i < nbParams; ++i) {