Salome HOME
[EDF] (2023-T1) Sketch middle point constrain should create point if missing CR35150 10/head
authorasozinov <alexey.sozinov@opencascade.com>
Tue, 6 Jun 2023 10:52:31 +0000 (11:52 +0100)
committerasozinov <alexey.sozinov@opencascade.com>
Wed, 25 Oct 2023 10:36:25 +0000 (11:36 +0100)
- Added new way for create middle point constraint: Only by segment
- Added MacroMiddlePoint, which create point and middle constraint between point and passed object. Returns point
- SketchAPI: added setMiddlePoint() command, which pass only object and create middle point for object.
- will be updated documentation and tests

26 files changed:
src/SketchAPI/CMakeLists.txt
src/SketchAPI/SketchAPI.i
src/SketchAPI/SketchAPI_Constraint.cpp
src/SketchAPI/SketchAPI_Constraint.h
src/SketchAPI/SketchAPI_MacroMiddlePoint.cpp [new file with mode: 0644]
src/SketchAPI/SketchAPI_MacroMiddlePoint.h [new file with mode: 0644]
src/SketchAPI/SketchAPI_Sketch.cpp
src/SketchAPI/SketchAPI_Sketch.h
src/SketchAPI/SketchAPI_swig.h
src/SketchPlugin/SketchPlugin_ConstraintMiddle.cpp
src/SketchPlugin/SketchPlugin_ConstraintMiddle.h
src/SketchPlugin/Test/TestConstraintMiddlePoint.py
src/SketchPlugin/Test/TestConstraintMiddlePointOnArc.py
src/SketchPlugin/Test/TestConstraintMiddlePointOnEllipticArc.py
src/SketchPlugin/doc/examples/middle.py
src/SketchPlugin/doc/images/MiddlePoint_obj.png [new file with mode: 0644]
src/SketchPlugin/doc/images/Middlepoint_obj_panel.png [new file with mode: 0644]
src/SketchPlugin/doc/images/Middlepoint_obj_point_panel.png [new file with mode: 0644]
src/SketchPlugin/doc/images/Middlepoint_obj_point_res.png [new file with mode: 0644]
src/SketchPlugin/doc/images/Middlepoint_obj_res.png [new file with mode: 0644]
src/SketchPlugin/doc/images/Middlepoint_panel.png [deleted file]
src/SketchPlugin/doc/images/Middlepoint_res.png [deleted file]
src/SketchPlugin/doc/middleFeature.rst
src/SketchPlugin/icons/middlepoint_obj.png [new file with mode: 0644]
src/SketchPlugin/plugin-Sketch.xml
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp

index 2d07f9a20071eed86b73339d4edb5dfb5dec770b..e83046e9ec70c8eafe34d906edc5b9dad1150ae0 100644 (file)
@@ -32,6 +32,7 @@ SET(PROJECT_HEADERS
   SketchAPI_Line.h
   SketchAPI_MacroArc.h
   SketchAPI_MacroCircle.h
+  SketchAPI_MacroMiddlePoint.h
   SketchAPI_MacroEllipse.h
   SketchAPI_MacroEllipticArc.h
   SketchAPI_Mirror.h
@@ -57,6 +58,7 @@ SET(PROJECT_SOURCES
   SketchAPI_Line.cpp
   SketchAPI_MacroArc.cpp
   SketchAPI_MacroCircle.cpp
+  SketchAPI_MacroMiddlePoint.cpp
   SketchAPI_MacroEllipse.cpp
   SketchAPI_MacroEllipticArc.cpp
   SketchAPI_Mirror.cpp
index 19238b33b053f7fefe87de0d01cd419c7800541a..ab4de1120a56a1bb56524a86639dcc7847aaf84e 100644 (file)
@@ -81,6 +81,7 @@
 %shared_ptr(SketchAPI_Sketch)
 %shared_ptr(SketchAPI_SketchEntity)
 %shared_ptr(SketchAPI_Point)
+%shared_ptr(SketchAPI_MacroMiddlePoint)
 %shared_ptr(SketchAPI_Projection)
 %shared_ptr(SketchAPI_Rectangle)
 %shared_ptr(SketchAPI_Rotation)
 // all supported interfaces (the order is very important according dependencies: base class first)
 %include "SketchAPI_SketchEntity.h"
 %include "SketchAPI_Point.h"
+%include "SketchAPI_MacroMiddlePoint.h"
 %include "SketchAPI_IntersectionPoint.h"
 %include "SketchAPI_Line.h"
 %include "SketchAPI_Circle.h"
index 9149d2395b60afc98e15bd3461cabb62b2acfa35..d69c35f884c2aaf7aae9354b360b9d30dbd4f505 100644 (file)
@@ -21,6 +21,8 @@
 
 #include <ModelHighAPI_Dumper.h>
 #include <ModelHighAPI_Tools.h>
+#include <SketchAPI_SketchEntity.h>
+#include <SketchAPI_Point.h>
 
 #include <SketchPlugin_Constraint.h>
 #include <SketchPlugin_ConstraintCoincidence.h>
@@ -39,6 +41,7 @@
 #include <SketchPlugin_ConstraintTangent.h>
 #include <SketchPlugin_ConstraintVertical.h>
 #include <SketchPlugin_SketchEntity.h>
+#include <SketchPlugin_Point.h>
 
 #include <SketcherPrs_Tools.h>
 
@@ -198,35 +201,61 @@ void SketchAPI_Constraint::dump(ModelHighAPI_Dumper& theDumper) const
       return;
   }
 
-  // postpone constraint until all its attributes be dumped
-  if (!areAllAttributesDumped(theDumper))
-    return;
-
   const std::string& aSketchName = theDumper.parentName(aBase);
-  theDumper << aSketchName << "." << aSetter << "(";
 
-  bool isFirstAttr = true;
-  for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
-    AttributeRefAttrPtr aRefAttr = aBase->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
+  // Dump middle constraint by object
+  if (SketchPlugin_ConstraintMiddle::ID() == aBase->getKind() &&
+    aBase->string(SketchPlugin_ConstraintMiddle::MIDDLE_TYPE())->value() == SketchPlugin_ConstraintMiddle::MIDDLE_TYPE_BY_LINE())
+  {
+    FeaturePtr aFeature;
+    AttributeRefAttrPtr aPointRefAttr = aBase->refattr(SketchPlugin_Constraint::ATTRIBUTE(1));
+    AttributeRefAttrPtr aRefAttr = aBase->refattr(SketchPlugin_Constraint::ATTRIBUTE(0));
+
+    if (!theDumper.isDumped(aRefAttr))
+    {
+      theDumper.postpone(aBase);
+      return;
+    }
+    aFeature = ModelAPI_Feature::feature(aPointRefAttr->object());
+
+    theDumper.name(aFeature, false, true, true); // mark point as dumped
+
+    theDumper << theDumper.name(aFeature) << " = " << aSketchName << "." << aSetter << "(";
     if (aRefAttr && aRefAttr->isInitialized()) {
-      theDumper << (isFirstAttr ? "" : ", ") << aRefAttr;
-      isFirstAttr = false;
+      theDumper << aRefAttr;
     }
+    theDumper << ")" << std::endl;
   }
+  else
+  {
+    // postpone constraint until all its attributes be dumped
+    if (!areAllAttributesDumped(theDumper))
+      return;
+
+    theDumper << aSketchName << "." << aSetter << "(";
+    bool isFirstAttr = true;
+    for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
+      AttributeRefAttrPtr aRefAttr = aBase->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
+      if (aRefAttr && aRefAttr->isInitialized()) {
+        theDumper << (isFirstAttr ? "" : ", ") << aRefAttr;
+        isFirstAttr = false;
+      }
+    }
 
-  AttributeDoublePtr aValueAttr;
-  if (aBase->getKind() == SketchPlugin_ConstraintDistanceHorizontal::ID() ||
+    AttributeDoublePtr aValueAttr;
+    if (aBase->getKind() == SketchPlugin_ConstraintDistanceHorizontal::ID() ||
       aBase->getKind() == SketchPlugin_ConstraintDistanceVertical::ID())
-    aValueAttr = aBase->real(SketchPlugin_ConstraintDistanceAlongDir::DISTANCE_VALUE_ID());
-  else
-    aValueAttr = aBase->real(SketchPlugin_Constraint::VALUE());
-  if (aValueAttr && aValueAttr->isInitialized())
-    theDumper << ", " << aValueAttr;
+      aValueAttr = aBase->real(SketchPlugin_ConstraintDistanceAlongDir::DISTANCE_VALUE_ID());
+    else
+      aValueAttr = aBase->real(SketchPlugin_Constraint::VALUE());
+    if (aValueAttr && aValueAttr->isInitialized())
+      theDumper << ", " << aValueAttr;
 
-  if (aBase->getKind() == SketchPlugin_ConstraintDistance::ID()) {
-    AttributeBooleanPtr isSigned = aBase->boolean(SketchPlugin_ConstraintDistance::SIGNED());
-    theDumper << ", " << isSigned->value();
+    if (aBase->getKind() == SketchPlugin_ConstraintDistance::ID()) {
+      AttributeBooleanPtr isSigned = aBase->boolean(SketchPlugin_ConstraintDistance::SIGNED());
+      theDumper << ", " << isSigned->value();
+    }
+    theDumper << ")" << std::endl;
   }
 
-  theDumper << ")" << std::endl;
 }
index 220d1d59d86333e49895ee399567c3d11ad73cc6..fe4ece79142abaff7a6ec9a9d96121dd3ea0cf56 100644 (file)
@@ -29,6 +29,7 @@
 #include <SketchPlugin_Constraint.h>
 
 class ModelHighAPI_Double;
+class SketchAPI_SketchEntity;
 
 /**\class SketchAPI_Constraint
  * \ingroup CPPHighAPI
diff --git a/src/SketchAPI/SketchAPI_MacroMiddlePoint.cpp b/src/SketchAPI/SketchAPI_MacroMiddlePoint.cpp
new file mode 100644 (file)
index 0000000..3ec3a36
--- /dev/null
@@ -0,0 +1,71 @@
+// Copyright (C) 2019-2022  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 "SketchAPI_MacroMiddlePoint.h"
+
+#include <ModelHighAPI_RefAttr.h>
+
+#include <SketchPlugin_ConstraintMiddle.h>
+
+#include <cmath>
+
+SketchAPI_MacroMiddlePoint::SketchAPI_MacroMiddlePoint(
+    const std::shared_ptr<ModelAPI_Feature> & theFeature)
+: SketchAPI_Point(theFeature)
+{
+  ConstraintPtr aConstraint = std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
+  if (aConstraint)
+    initialize();
+}
+
+SketchAPI_MacroMiddlePoint::SketchAPI_MacroMiddlePoint(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+  const ModelHighAPI_RefAttr& theLine, const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
+  : SketchAPI_Point(theFeature, thePoint)
+{
+  createConstraint(theLine);
+}
+
+void SketchAPI_MacroMiddlePoint::createConstraint(const ModelHighAPI_RefAttr& theLine)
+{
+  // Find sketch
+  CompositeFeaturePtr aSketch;
+  const std::set<AttributePtr>& aRefs = feature()->data()->refsToMe();
+  for (std::set<AttributePtr>::const_iterator anIt = aRefs.begin(); anIt != aRefs.end(); ++anIt)
+    if ((*anIt)->id() == SketchPlugin_Sketch::FEATURES_ID())
+    {
+      aSketch = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>((*anIt)->owner());
+      break;
+    }
+  if (!aSketch)
+    return;
+
+  // Create middle constraint for line and poiunt
+  std::shared_ptr<ModelAPI_Feature> aConstrFeature =
+    aSketch->addFeature(SketchPlugin_ConstraintMiddle::ID());
+  aConstrFeature->string(SketchPlugin_ConstraintMiddle::MIDDLE_TYPE())->setValue(SketchPlugin_ConstraintMiddle::MIDDLE_TYPE_BY_LINE());
+  aConstrFeature->refattr(SketchPlugin_Constraint::ENTITY_A())->setObject(theLine.object());
+  aConstrFeature->refattr(SketchPlugin_Constraint::ENTITY_B())->setAttr(coordinates());
+  std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aConstrFeature->attribute(SketchPlugin_ConstraintMiddle::POINT_REF_ID()))->setValue(coordinates()->x(), coordinates()->y());
+
+  aConstrFeature->execute();
+
+  feature()->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(true);
+  feature()->reference(SketchPlugin_SketchEntity::PARENT_ID())->setValue(aConstrFeature);
+  feature()->execute();
+}
diff --git a/src/SketchAPI/SketchAPI_MacroMiddlePoint.h b/src/SketchAPI/SketchAPI_MacroMiddlePoint.h
new file mode 100644 (file)
index 0000000..2e747df
--- /dev/null
@@ -0,0 +1,58 @@
+// Copyright (C) 2019-2022  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 SRC_SKETCHAPI_SKETCHAPI_MACRO_MIDDLEPOINT_H_
+#define SRC_SKETCHAPI_SKETCHAPI_MACRO_MIDDLEPOINT_H_
+
+#include "SketchAPI_SketchEntity.h"
+
+#include <SketchAPI_Point.h>
+
+class ModelHighAPI_RefAttr;
+
+
+/**\class SketchAPI_MacroMiddlePoint
+ * \ingroup CPPHighAPI
+ * \brief Interface for Middle Point feature
+ */
+class SketchAPI_MacroMiddlePoint : public SketchAPI_Point
+{
+public:
+  /// Constructor without values
+  SKETCHAPI_EXPORT
+  explicit SketchAPI_MacroMiddlePoint(const std::shared_ptr<ModelAPI_Feature> & theFeature);
+
+  /// Constructor with line and middle point coordinates
+  SKETCHAPI_EXPORT
+    SketchAPI_MacroMiddlePoint(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+      const ModelHighAPI_RefAttr& theLine,
+      const std::shared_ptr<GeomAPI_Pnt2d>& thePoint);
+
+  static std::string ID()
+  {
+    static const std::string MY_SKETCH_CONSTRAINT_ID = "MacroConstraintMiddle";
+    return MY_SKETCH_CONSTRAINT_ID;
+  }
+  virtual std::string getID() { return ID(); }
+
+protected:
+  void createConstraint(const ModelHighAPI_RefAttr& theLine);
+};
+
+#endif
index 34503d972d49f04a3484a5eb3b588b722169c504..b0836ae1219b50013cf6d621c3b1fd29646b7f09 100644 (file)
@@ -67,6 +67,7 @@
 #include "SketchAPI_MacroCircle.h"
 #include "SketchAPI_MacroEllipse.h"
 #include "SketchAPI_MacroEllipticArc.h"
+#include "SketchAPI_MacroMiddlePoint.h"
 #include "SketchAPI_Mirror.h"
 #include "SketchAPI_Offset.h"
 #include "SketchAPI_Point.h"
@@ -74,6 +75,7 @@
 #include "SketchAPI_Rectangle.h"
 #include "SketchAPI_Rotation.h"
 #include "SketchAPI_Translation.h"
+#include "SketchAPI_Constraint.h"
 //--------------------------------------------------------------------------------------
 #include <GeomAPI_Curve.h>
 #include <GeomAPI_Dir2d.h>
 #include <algorithm>
 #include <cmath>
 //--------------------------------------------------------------------------------------
+
+
+static std::shared_ptr<GeomAPI_Pnt2d> pointCoordinates(const AttributePtr& thePoint)
+{
+  AttributePoint2DPtr aPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(thePoint);
+  return aPnt ? aPnt->pnt() : std::shared_ptr<GeomAPI_Pnt2d>();
+}
+
+static std::shared_ptr<GeomAPI_Pnt2d> middlePointOnLine(const FeaturePtr& theFeature)
+{
+  AttributePoint2DPtr aStartAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+    theFeature->attribute(SketchPlugin_Line::START_ID()));
+  AttributePoint2DPtr aEndAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+    theFeature->attribute(SketchPlugin_Line::END_ID()));
+
+  if (!aStartAttr || !aEndAttr)
+    return std::shared_ptr<GeomAPI_Pnt2d>();
+
+  std::shared_ptr<GeomAPI_XY> aStartPoint = aStartAttr->pnt()->xy();
+  std::shared_ptr<GeomAPI_XY> aEndPoint = aEndAttr->pnt()->xy();
+  return std::shared_ptr<GeomAPI_Pnt2d>(
+    new GeomAPI_Pnt2d(aStartPoint->added(aEndPoint)->multiplied(0.5)));
+}
+
+static std::shared_ptr<GeomAPI_Pnt2d> pointOnCircle(const FeaturePtr& theFeature)
+{
+  AttributePoint2DPtr aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+    theFeature->attribute(SketchPlugin_Circle::CENTER_ID()));
+  AttributeDoublePtr aRadius = theFeature->real(SketchPlugin_Circle::RADIUS_ID());
+
+  if (!aCenter || !aRadius)
+    return std::shared_ptr<GeomAPI_Pnt2d>();
+
+  return std::shared_ptr<GeomAPI_Pnt2d>(
+    new GeomAPI_Pnt2d(aCenter->x() + aRadius->value(), aCenter->y()));
+}
+
+static std::shared_ptr<GeomAPI_Pnt2d> middlePointOnArc(const FeaturePtr& theFeature)
+{
+  static const double PI = 3.141592653589793238463;
+
+  AttributePoint2DPtr aCenterAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+    theFeature->attribute(SketchPlugin_Arc::CENTER_ID()));
+  AttributePoint2DPtr aStartAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+    theFeature->attribute(SketchPlugin_Arc::START_ID()));
+  AttributePoint2DPtr aEndAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+    theFeature->attribute(SketchPlugin_Arc::END_ID()));
+
+  if (!aCenterAttr || !aStartAttr || !aEndAttr)
+    return std::shared_ptr<GeomAPI_Pnt2d>();
+
+  std::shared_ptr<GeomAPI_Dir2d> aStartDir(new GeomAPI_Dir2d(
+    aStartAttr->x() - aCenterAttr->x(), aStartAttr->y() - aCenterAttr->y()));
+  std::shared_ptr<GeomAPI_Dir2d> aEndDir(new GeomAPI_Dir2d(
+    aEndAttr->x() - aCenterAttr->x(), aEndAttr->y() - aCenterAttr->y()));
+
+  double anAngle = aStartDir->angle(aEndDir);
+  bool isReversed = theFeature->boolean(SketchPlugin_Arc::REVERSED_ID())->value();
+  if (isReversed && anAngle > 0.)
+    anAngle -= 2.0 * PI;
+  else if (!isReversed && anAngle <= 0.)
+    anAngle += 2.0 * PI;
+
+  double cosA = cos(anAngle);
+  double sinA = sin(anAngle);
+
+  // rotate start dir to find middle point on arc
+  double aRadius = aStartAttr->pnt()->distance(aCenterAttr->pnt());
+  double x = aCenterAttr->x() + aRadius * (aStartDir->x() * cosA - aStartDir->y() * sinA);
+  double y = aCenterAttr->y() + aRadius * (aStartDir->x() * sinA + aStartDir->y() * cosA);
+
+  return std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(x, y));
+}
+
+static std::shared_ptr<GeomAPI_Pnt2d> pointOnEllipse(const FeaturePtr& theFeature,
+  bool isEllipse = true)
+{
+  const std::string& anAttrName = isEllipse ? SketchPlugin_Ellipse::MAJOR_AXIS_END_ID() :
+    SketchPlugin_EllipticArc::MAJOR_AXIS_END_ID();
+  AttributePoint2DPtr aMajorAxisEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+    theFeature->attribute(anAttrName));
+  return aMajorAxisEnd ? aMajorAxisEnd->pnt() : std::shared_ptr<GeomAPI_Pnt2d>();
+}
+
+static std::shared_ptr<GeomAPI_Pnt2d> middlePointOnBSpline(const FeaturePtr& theFeature,
+  SketchAPI_Sketch* theSketch)
+{
+  GeomAPI_Edge anEdge(theFeature->lastResult()->shape());
+  GeomPointPtr aMiddle = anEdge.middlePoint();
+  return theSketch->to2D(aMiddle);
+}
+
+static std::shared_ptr<GeomAPI_Pnt2d> middlePoint(const ObjectPtr& theObject,
+  SketchAPI_Sketch* theSketch)
+{
+  std::shared_ptr<GeomAPI_Pnt2d> aMiddlePoint;
+  FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
+  if (aFeature) {
+    // move only features of the following types
+    const std::string& aFeatureKind = aFeature->getKind();
+    if (aFeatureKind == SketchPlugin_Point::ID())
+      aMiddlePoint = pointCoordinates(aFeature->attribute(SketchPlugin_Point::COORD_ID()));
+    else if (aFeatureKind == SketchPlugin_Line::ID())
+      aMiddlePoint = middlePointOnLine(aFeature);
+    else if (aFeatureKind == SketchPlugin_Circle::ID())
+      aMiddlePoint = pointOnCircle(aFeature);
+    else if (aFeatureKind == SketchPlugin_Arc::ID())
+      aMiddlePoint = middlePointOnArc(aFeature);
+    else if (aFeatureKind == SketchPlugin_Ellipse::ID())
+      aMiddlePoint = pointOnEllipse(aFeature);
+    else if (aFeatureKind == SketchPlugin_EllipticArc::ID())
+      aMiddlePoint = pointOnEllipse(aFeature, false);
+    else if (aFeatureKind == SketchPlugin_BSpline::ID() ||
+      aFeatureKind == SketchPlugin_BSplinePeriodic::ID())
+      aMiddlePoint = middlePointOnBSpline(aFeature, theSketch);
+  }
+  return aMiddlePoint;
+}
+
 SketchAPI_Sketch::SketchAPI_Sketch(
     const std::shared_ptr<ModelAPI_Feature> & theFeature)
 : ModelHighAPI_Interface(theFeature)
@@ -1246,12 +1367,29 @@ std::shared_ptr<ModelHighAPI_Interface> SketchAPI_Sketch::setMiddlePoint(
 {
   std::shared_ptr<ModelAPI_Feature> aFeature =
       compositeFeature()->addFeature(SketchPlugin_ConstraintMiddle::ID());
+  auto aType = aFeature->data()->string(SketchPlugin_ConstraintMiddle::MIDDLE_TYPE());
+  fillAttribute(SketchPlugin_ConstraintMiddle::MIDDLE_TYPE_BY_LINE_AND_POINT(), aType);
+
   fillAttribute(thePoint, aFeature->refattr(SketchPlugin_Constraint::ENTITY_A()));
   fillAttribute(theLine, aFeature->refattr(SketchPlugin_Constraint::ENTITY_B()));
+
   aFeature->execute();
   return InterfacePtr(new ModelHighAPI_Interface(aFeature));
 }
 
+std::shared_ptr<SketchAPI_MacroMiddlePoint> SketchAPI_Sketch::setMiddlePoint(
+  const ModelHighAPI_RefAttr& theLine)
+{
+  std::shared_ptr<ModelAPI_Feature> aFeature =
+    compositeFeature()->addFeature(SketchPlugin_Point::ID());
+
+  ObjectPtr anObj = theLine.object();
+  auto aPoint = middlePoint(anObj, this);
+
+  return std::shared_ptr<SketchAPI_MacroMiddlePoint>
+    (new SketchAPI_MacroMiddlePoint(aFeature, theLine, aPoint));
+}
+
 std::shared_ptr<ModelHighAPI_Interface> SketchAPI_Sketch::setParallel(
     const ModelHighAPI_RefAttr & theLine1,
     const ModelHighAPI_RefAttr & theLine2)
@@ -1312,123 +1450,6 @@ std::shared_ptr<ModelHighAPI_Interface> SketchAPI_Sketch::setVertical(
 
 //--------------------------------------------------------------------------------------
 
-static std::shared_ptr<GeomAPI_Pnt2d> pointCoordinates(const AttributePtr& thePoint)
-{
-  AttributePoint2DPtr aPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(thePoint);
-  return aPnt ? aPnt->pnt() : std::shared_ptr<GeomAPI_Pnt2d>();
-}
-
-static std::shared_ptr<GeomAPI_Pnt2d> middlePointOnLine(const FeaturePtr& theFeature)
-{
-  AttributePoint2DPtr aStartAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theFeature->attribute(SketchPlugin_Line::START_ID()));
-  AttributePoint2DPtr aEndAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theFeature->attribute(SketchPlugin_Line::END_ID()));
-
-  if (!aStartAttr || !aEndAttr)
-    return std::shared_ptr<GeomAPI_Pnt2d>();
-
-  std::shared_ptr<GeomAPI_XY> aStartPoint = aStartAttr->pnt()->xy();
-  std::shared_ptr<GeomAPI_XY> aEndPoint = aEndAttr->pnt()->xy();
-  return std::shared_ptr<GeomAPI_Pnt2d>(
-      new GeomAPI_Pnt2d(aStartPoint->added(aEndPoint)->multiplied(0.5)));
-}
-
-static std::shared_ptr<GeomAPI_Pnt2d> pointOnCircle(const FeaturePtr& theFeature)
-{
-  AttributePoint2DPtr aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theFeature->attribute(SketchPlugin_Circle::CENTER_ID()));
-  AttributeDoublePtr aRadius = theFeature->real(SketchPlugin_Circle::RADIUS_ID());
-
-  if (!aCenter || !aRadius)
-    return std::shared_ptr<GeomAPI_Pnt2d>();
-
-  return std::shared_ptr<GeomAPI_Pnt2d>(
-      new GeomAPI_Pnt2d(aCenter->x() + aRadius->value(), aCenter->y()));
-}
-
-static std::shared_ptr<GeomAPI_Pnt2d> middlePointOnArc(const FeaturePtr& theFeature)
-{
-  static const double PI = 3.141592653589793238463;
-
-  AttributePoint2DPtr aCenterAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theFeature->attribute(SketchPlugin_Arc::CENTER_ID()));
-  AttributePoint2DPtr aStartAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theFeature->attribute(SketchPlugin_Arc::START_ID()));
-  AttributePoint2DPtr aEndAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theFeature->attribute(SketchPlugin_Arc::END_ID()));
-
-  if (!aCenterAttr || !aStartAttr || !aEndAttr)
-    return std::shared_ptr<GeomAPI_Pnt2d>();
-
-  std::shared_ptr<GeomAPI_Dir2d> aStartDir(new GeomAPI_Dir2d(
-      aStartAttr->x() - aCenterAttr->x(), aStartAttr->y() - aCenterAttr->y()));
-  std::shared_ptr<GeomAPI_Dir2d> aEndDir(new GeomAPI_Dir2d(
-      aEndAttr->x() - aCenterAttr->x(), aEndAttr->y() - aCenterAttr->y()));
-
-  double anAngle = aStartDir->angle(aEndDir);
-  bool isReversed = theFeature->boolean(SketchPlugin_Arc::REVERSED_ID())->value();
-  if (isReversed && anAngle > 0.)
-    anAngle -= 2.0 * PI;
-  else if (!isReversed && anAngle <= 0.)
-    anAngle += 2.0 * PI;
-
-  double cosA = cos(anAngle);
-  double sinA = sin(anAngle);
-
-  // rotate start dir to find middle point on arc
-  double aRadius = aStartAttr->pnt()->distance(aCenterAttr->pnt());
-  double x = aCenterAttr->x() + aRadius * (aStartDir->x() * cosA - aStartDir->y() * sinA);
-  double y = aCenterAttr->y() + aRadius * (aStartDir->x() * sinA + aStartDir->y() * cosA);
-
-  return std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(x, y));
-}
-
-static std::shared_ptr<GeomAPI_Pnt2d> pointOnEllipse(const FeaturePtr& theFeature,
-                                                     bool isEllipse = true)
-{
-  const std::string& anAttrName = isEllipse ? SketchPlugin_Ellipse::MAJOR_AXIS_END_ID() :
-                                  SketchPlugin_EllipticArc::MAJOR_AXIS_END_ID();
-  AttributePoint2DPtr aMajorAxisEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theFeature->attribute(anAttrName));
-  return aMajorAxisEnd ? aMajorAxisEnd->pnt() : std::shared_ptr<GeomAPI_Pnt2d>();
-}
-
-static std::shared_ptr<GeomAPI_Pnt2d> middlePointOnBSpline(const FeaturePtr& theFeature,
-                                                           SketchAPI_Sketch* theSketch)
-{
-  GeomAPI_Edge anEdge(theFeature->lastResult()->shape());
-  GeomPointPtr aMiddle = anEdge.middlePoint();
-  return theSketch->to2D(aMiddle);
-}
-
-static std::shared_ptr<GeomAPI_Pnt2d> middlePoint(const ObjectPtr& theObject,
-                                                  SketchAPI_Sketch* theSketch)
-{
-  std::shared_ptr<GeomAPI_Pnt2d> aMiddlePoint;
-  FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
-  if (aFeature) {
-    // move only features of the following types
-    const std::string& aFeatureKind = aFeature->getKind();
-    if (aFeatureKind == SketchPlugin_Point::ID())
-      aMiddlePoint = pointCoordinates(aFeature->attribute(SketchPlugin_Point::COORD_ID()));
-    else if (aFeatureKind == SketchPlugin_Line::ID())
-      aMiddlePoint = middlePointOnLine(aFeature);
-    else if (aFeatureKind == SketchPlugin_Circle::ID())
-      aMiddlePoint = pointOnCircle(aFeature);
-    else if (aFeatureKind == SketchPlugin_Arc::ID())
-      aMiddlePoint = middlePointOnArc(aFeature);
-    else if (aFeatureKind == SketchPlugin_Ellipse::ID())
-      aMiddlePoint = pointOnEllipse(aFeature);
-    else if (aFeatureKind == SketchPlugin_EllipticArc::ID())
-      aMiddlePoint = pointOnEllipse(aFeature, false);
-    else if (aFeatureKind == SketchPlugin_BSpline::ID() ||
-             aFeatureKind == SketchPlugin_BSplinePeriodic::ID())
-      aMiddlePoint = middlePointOnBSpline(aFeature, theSketch);
-  }
-  return aMiddlePoint;
-}
-
 void SketchAPI_Sketch::move(const ModelHighAPI_RefAttr& theMovedEntity,
                             const std::shared_ptr<GeomAPI_Pnt2d>& theTargetPoint)
 {
index f9c8fdb794d06d4fa73491feadac9ca06837e995..993e6ef901536e95e39316e17c17c648863da9bd 100644 (file)
@@ -57,6 +57,7 @@ class SketchAPI_Projection;
 class SketchAPI_Rectangle;
 class SketchAPI_Rotation;
 class SketchAPI_Translation;
+class SketchAPI_MacroMiddlePoint;
 
 //--------------------------------------------------------------------------------------
 typedef std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr> PointOrReference;
@@ -523,6 +524,11 @@ public:
       const ModelHighAPI_RefAttr & thePoint,
       const ModelHighAPI_RefAttr & theLine);
 
+  /// Set middle
+  SKETCHAPI_EXPORT
+    std::shared_ptr<SketchAPI_MacroMiddlePoint> setMiddlePoint(
+      const ModelHighAPI_RefAttr& theLine);
+
   /// Set parallel
   SKETCHAPI_EXPORT
   std::shared_ptr<ModelHighAPI_Interface> setParallel(
index 9fb8e62116cfec19d4e7d14afdcce99601d7bd79..111782427ee961b59ab3abd2bf657d9d3c98353f 100644 (file)
@@ -41,6 +41,7 @@
   #include "SketchAPI_Sketch.h"
   #include "SketchAPI_SketchEntity.h"
   #include "SketchAPI_Point.h"
+  #include "SketchAPI_MacroMiddlePoint.h"
   #include "SketchAPI_Projection.h"
   #include "SketchAPI_Rectangle.h"
   #include "SketchAPI_Rotation.h"
index ad9ab375593c4ed2476952e8ca3c5d1cd2d80fac..9d478833b9d44ff94445cb1572fbb09c2d960587 100644 (file)
 
 #include "SketcherPrs_Factory.h"
 
+#include <GeomDataAPI_Point2D.h>
+
+#include <ModelAPI_Validator.h>
+#include <ModelAPI_AttributeString.h>
+
+#include <ModelAPI_Events.h>
+#include <SketchPlugin_Point.h>
+#include <SketchPlugin_Tools.h>
+
 SketchPlugin_ConstraintMiddle::SketchPlugin_ConstraintMiddle()
 {
 }
 
+// Create new point for Middle constraint
+void SketchPlugin_ConstraintMiddle::CreatePoint()
+{
+  // Wait all objects being created, then send update events
+  static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
+  bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
+  if (isUpdateFlushed)
+    Events_Loop::loop()->setFlushed(anUpdateEvent, false);
+
+  auto aTrPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(POINT_REF_ID()));
+
+  if (!myPoint)
+  {
+    // Get last subfeature (constraintMiddle) for set as parent
+    FeaturePtr aCurrentFeature = sketch()->subFeature(sketch()->numberOfSubs() - 1);
+    keepCurrentFeature();
+    myPoint = sketch()->addFeature(SketchPlugin_Point::ID());
+    myPoint->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(true);
+    restoreCurrentFeature();
+
+    myPoint->reference(SketchPlugin_Point::PARENT_ID())->setValue(aCurrentFeature);
+  }
+
+  AttributePoint2DPtr aCoord = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+    myPoint->attribute(SketchPlugin_Point::COORD_ID()));
+  aCoord->setValue(aTrPnt->pnt());
+
+  myPoint->execute();
+
+  // Init second attr for constraint
+  refattr(SketchPlugin_Constraint::ENTITY_B())->setObject(myPoint);
+
+
+  if (isUpdateFlushed)
+    Events_Loop::loop()->setFlushed(anUpdateEvent, true);
+}
+
 void SketchPlugin_ConstraintMiddle::initAttributes()
 {
+  data()->addAttribute(SketchPlugin_ConstraintMiddle::MIDDLE_TYPE(), ModelAPI_AttributeString::typeId());
+
   data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
   data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
+
+  data()->addAttribute(POINT_REF_ID(), GeomDataAPI_Point2D::typeId());
+
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), POINT_REF_ID());
 }
 
 void SketchPlugin_ConstraintMiddle::execute()
 {
+  if (string(MIDDLE_TYPE())->value() == MIDDLE_TYPE_BY_LINE())
+  {
+    std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(POINT_REF_ID()))->setValue(1., 1.);
+    AttributeRefAttrPtr aPointRes = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+      data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
+
+    auto aRefAttr = data()->refattr(SketchPlugin_Constraint::ENTITY_A())->object();
+    if (!aRefAttr.get())
+      return;
+
+
+    if (!attribute(ENTITY_B())->isInitialized())
+      CreatePoint(); // Create new point
+  }
+}
+
+void SketchPlugin_ConstraintMiddle::attributeChanged(const std::string& theID)
+{
+  if (theID == MIDDLE_TYPE())
+  {
+    SketchPlugin_Tools::resetAttribute(this, ENTITY_A());
+    SketchPlugin_Tools::resetAttribute(this, ENTITY_B());
+  }
+  else if (theID == POINT_REF_ID())
+  {
+    if (!myPoint)
+      return;
+
+    auto aTrPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(POINT_REF_ID()));
+    AttributePoint2DPtr aCoord = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      myPoint->attribute(SketchPlugin_Point::COORD_ID()));
+    aCoord->setValue(aTrPnt->pnt());
+
+    myPoint->execute();
+  }
 }
 
 AISObjectPtr SketchPlugin_ConstraintMiddle::getAISObject(AISObjectPtr thePrevious)
 {
   if (!sketch())
     return thePrevious;
-
   AISObjectPtr anAIS = SketcherPrs_Factory::middleConstraint(this, sketch(),
                                                              thePrevious);
+
   return anAIS;
 }
-
-
index 6c0ac43ce8f998307d72c14eeadcd1cdb4e0592b..ddb3c2faa60150453b4b2f5ed3b90a9170b29e82 100644 (file)
@@ -24,6 +24,8 @@
 #include <SketchPlugin_Sketch.h>
 #include "SketchPlugin_ConstraintBase.h"
 
+class ModelAPI_Feature;
+
 /** \class SketchPlugin_ConstraintMiddle
  *  \ingroup Plugins
  *  \brief Feature for creation of a new constraint which places a point in the middle of a line
@@ -40,6 +42,35 @@ class SketchPlugin_ConstraintMiddle : public SketchPlugin_ConstraintBase
     static const std::string MY_CONSTRAINT_MIDDLE_ID("SketchConstraintMiddle");
     return MY_CONSTRAINT_MIDDLE_ID;
   }
+
+  /// Middle constraint kind
+  inline static const std::string& MIDDLE_TYPE()
+  {
+    static const std::string MY_TYPE_ID("middle_type");
+    return MY_TYPE_ID;
+  }
+
+  /// Middle constraint type by line and point
+  inline static const std::string& MIDDLE_TYPE_BY_LINE_AND_POINT()
+  {
+    static const std::string MY_TYPE_ID("middle_type_by_line_and_point");
+    return MY_TYPE_ID;
+  }
+
+  /// Middle constraint type by line
+  inline static const std::string& MIDDLE_TYPE_BY_LINE()
+  {
+    static const std::string MY_TYPE_ID("middle_type_by_line");
+    return MY_TYPE_ID;
+  }
+
+  /// Created points for middle type by line
+  inline static const std::string& POINT_REF_ID()
+  {
+    static const std::string MY_POINT_REF("point");
+    return MY_POINT_REF;
+  }
+
   /// \brief Returns the kind of a feature
   SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
   {
@@ -47,6 +78,9 @@ class SketchPlugin_ConstraintMiddle : public SketchPlugin_ConstraintBase
     return MY_KIND;
   }
 
+  /// Called on change of any argument-attribute of this object
+  SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID);
+
   /// \brief Creates a new part document if needed
   SKETCHPLUGIN_EXPORT virtual void execute();
 
@@ -58,6 +92,11 @@ class SketchPlugin_ConstraintMiddle : public SketchPlugin_ConstraintBase
 
   /// \brief Use plugin manager for features creation
   SketchPlugin_ConstraintMiddle();
+
+private:
+  void CreatePoint();
+
+  std::shared_ptr<ModelAPI_Feature> myPoint;
 };
 
 #endif
index 36aef57cf2571fc3d3ac84b883180b234d64634b..9814bb73165b5ca8e9f16e0b2098a8a61548ef21 100644 (file)
@@ -37,6 +37,7 @@
 """
 from GeomDataAPI import *
 from ModelAPI import *
+from SketchAPI import *
 import math
 from salome.shaper import model
 
@@ -105,6 +106,8 @@ aSession.startOperation()
 aConstraint = aSketchFeature.addFeature("SketchConstraintMiddle")
 reflistA = aConstraint.refattr("ConstraintEntityA")
 reflistB = aConstraint.refattr("ConstraintEntityB")
+anAlgoType = aConstraint.string("middle_type")
+anAlgoType.setValue("middle_type_by_line_and_point")
 reflistA.setAttr(aEndPoint2)
 reflistB.setObject(aLine1.lastResult())
 aConstraint.execute()
@@ -122,6 +125,8 @@ aEndPoint2.setValue(80., 25.)
 aConstraint = aSketchFeature.addFeature("SketchConstraintMiddle")
 reflistA = aConstraint.refattr("ConstraintEntityA")
 reflistB = aConstraint.refattr("ConstraintEntityB")
+anAlgoType = aConstraint.string("middle_type")
+anAlgoType.setValue("middle_type_by_line_and_point")
 reflistA.setAttr(aEndPoint2)
 reflistB.setObject(aLine1.lastResult())
 aConstraint.execute()
@@ -172,6 +177,8 @@ aSession.startOperation()
 aConstraint = aSketchFeature.addFeature("SketchConstraintMiddle")
 reflistA = aConstraint.refattr("ConstraintEntityA")
 reflistB = aConstraint.refattr("ConstraintEntityB")
+anAlgoType = aConstraint.string("middle_type")
+anAlgoType.setValue("middle_type_by_line_and_point")
 reflistA.setObject(aLine2.lastResult())
 reflistB.setObject(anOrigin.lastResult())
 aSession.finishOperation()
@@ -205,6 +212,8 @@ aSession.startOperation()
 aMiddle = aSketchFeature.addFeature("SketchConstraintMiddle")
 reflistA = aMiddle.refattr("ConstraintEntityA")
 reflistB = aMiddle.refattr("ConstraintEntityB")
+anAlgoType = aMiddle.string("middle_type")
+anAlgoType.setValue("middle_type_by_line_and_point")
 reflistA.setAttr(aEndPoint3)
 reflistB.setObject(aLine1.lastResult())
 aSession.finishOperation()
@@ -225,6 +234,37 @@ aEndPoint1.setValue(aEndPoint1.x() + deltaX, aEndPoint1.y() + deltaY)
 aSession.finishOperation()
 checkMiddlePoint(aEndPoint3, aLine1)
 assert (model.dof(aSketchFeature) == 8)
+#=========================================================================
+# CreateLine
+#=========================================================================
+aSession.startOperation()
+aLine4 = aSketchFeature.addFeature("SketchLine")
+aStartPoint4 = geomDataAPI_Point2D(aLine4.attribute("StartPoint"))
+aEndPoint4 = geomDataAPI_Point2D(aLine4.attribute("EndPoint"))
+aStartPoint4.setValue(2., 8.)
+aEndPoint4.setValue(20., 14.)
+aRigidConstraint1 = aSketchFeature.addFeature("SketchConstraintRigid")
+aRigidConstraint1.refattr("ConstraintEntityA").setAttr(aStartPoint4)
+aRigidConstraint2 = aSketchFeature.addFeature("SketchConstraintRigid")
+aRigidConstraint2.refattr("ConstraintEntityA").setAttr(aEndPoint4)
+aSession.finishOperation()
+#=========================================================================
+# Set middle point on line
+#=========================================================================
+aSession.startOperation()
+aMiddle = aSketchFeature.addFeature("SketchConstraintMiddle")
+reflistA = aMiddle.refattr("ConstraintEntityA")
+anAlgoType = aMiddle.string("middle_type")
+anAlgoType.setValue("middle_type_by_line")
+reflistA.setObject(aLine4.lastResult())
+aSession.finishOperation()
+arefB = aMiddle.refattr("ConstraintEntityB")
+aPointRes = ModelAPI_Feature.feature(arefB.object())
+aMidPoint = geomDataAPI_Point2D(SketchAPI_Point(aPointRes).coordinates())
+
+# check the point, and no error message
+checkMiddlePoint(aMidPoint, aLine4)
+
 
 #=========================================================================
 # End of test
index 3312d07eacf3ae95c0a7ac3df0e02af8da8cc21c..208cbf7d8014dbd62ce0d07da011fe3e050dcec6 100644 (file)
@@ -44,7 +44,7 @@ class TestMiddlePointOnArc(unittest.TestCase):
   def tearDown(self):
     if self.myTestPassed:
       model.assertArcValidity(self.myArc)
-      self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+      self.checkMiddlePoint(self.myLine.startPoint().pnt(), self.myArc)
       self.checkDOF()
     model.end()
     assert(model.checkPythonDump())
@@ -55,7 +55,7 @@ class TestMiddlePointOnArc(unittest.TestCase):
   def checkMiddlePoint(self, thePoint, theArc):
     self.myTestPassed = False
     # check point on arc
-    dist = thePoint.pnt().distance(theArc.center().pnt())
+    dist = thePoint.distance(theArc.center().pnt())
     NB_DIGITS = 7 - math.floor(math.log10(theArc.radius().value()))
     self.assertAlmostEqual(dist, theArc.radius().value(), NB_DIGITS)
     # check middle point
@@ -86,14 +86,14 @@ class TestMiddlePointOnArc(unittest.TestCase):
     while fullAngle < ANGLE_THRESHOLD:
       self.rotatePoint(self.myArc.startPoint(), self.myArc.center(), -ANGLE_STEP)
       model.do()
-      self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+      self.checkMiddlePoint(self.myLine.startPoint().pnt(), self.myArc)
       fullAngle += ANGLE_STEP
     # move start point of the arc conterclockwise
     fullAngle = 0.0
     while fullAngle < ANGLE_THRESHOLD:
       self.rotatePoint(self.myArc.startPoint(), self.myArc.center(), ANGLE_STEP)
       model.do()
-      self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+      self.checkMiddlePoint(self.myLine.startPoint().pnt(), self.myArc)
       fullAngle += ANGLE_STEP
 
     # move end point of the arc clockwise
@@ -101,14 +101,14 @@ class TestMiddlePointOnArc(unittest.TestCase):
     while fullAngle < ANGLE_THRESHOLD:
       self.rotatePoint(self.myArc.endPoint(), self.myArc.center(), -ANGLE_STEP)
       model.do()
-      self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+      self.checkMiddlePoint(self.myLine.startPoint().pnt(), self.myArc)
       fullAngle += ANGLE_STEP
     # move end point of the arc conterclockwise
     fullAngle = 0.0
     while fullAngle < ANGLE_THRESHOLD:
       self.rotatePoint(self.myArc.endPoint(), self.myArc.center(), ANGLE_STEP)
       model.do()
-      self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+      self.checkMiddlePoint(self.myLine.startPoint().pnt(), self.myArc)
       fullAngle += ANGLE_STEP
 
     # move center of the arc
@@ -118,14 +118,14 @@ class TestMiddlePointOnArc(unittest.TestCase):
         DELTA = [-DELTA[0], -DELTA[1]]
       self.mySketch.move(self.myArc.center(), self.myArc.center().x() + DELTA[0], self.myArc.center().y() + DELTA[1])
       model.do()
-      self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+      self.checkMiddlePoint(self.myLine.startPoint().pnt(), self.myArc)
     DELTA = [-1.0, 1.0]
     for i in range(0, 40):
       if i == 10 or i == 30:
         DELTA = [-DELTA[0], -DELTA[1]]
       self.mySketch.move(self.myArc.center(), self.myArc.center().x() + DELTA[0], self.myArc.center().y() + DELTA[1])
       model.do()
-      self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+      self.checkMiddlePoint(self.myLine.startPoint().pnt(), self.myArc)
 
   def moveLine(self):
     DELTA = [1.0, 0.0]
@@ -134,14 +134,14 @@ class TestMiddlePointOnArc(unittest.TestCase):
         DELTA = [-DELTA[0], -DELTA[1]]
       self.mySketch.move(self.myLine.startPoint(), self.myLine.startPoint().x() + DELTA[0], self.myLine.startPoint().y() + DELTA[1])
       model.do()
-      self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+      self.checkMiddlePoint(self.myLine.startPoint().pnt(), self.myArc)
     DELTA = [0.0, 1.0]
     for i in range(0, 40):
       if i == 10 or i == 30:
         DELTA = [-DELTA[0], -DELTA[1]]
       self.mySketch.move(self.myLine.startPoint(), self.myLine.startPoint().x() + DELTA[0], self.myLine.startPoint().y() + DELTA[1])
       model.do()
-      self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+      self.checkMiddlePoint(self.myLine.startPoint().pnt(), self.myArc)
 
 
   def test_middle_point_PA(self):
@@ -187,7 +187,7 @@ class TestMiddlePointOnArc(unittest.TestCase):
     self.myDOF -= 2
     model.do()
     # this check will fail due to the limitation of PlanGCS
-    self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+    self.checkMiddlePoint(self.myLine.startPoint().pnt(), self.myArc)
 
   def test_middle_point_move_arc(self):
     """ Test 6. Set middle point constraint and move arc
@@ -195,7 +195,7 @@ class TestMiddlePointOnArc(unittest.TestCase):
     self.mySketch.setMiddlePoint(self.myLine.startPoint(), self.myArc.results()[1])
     self.myDOF -= 2
     model.do()
-    self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+    self.checkMiddlePoint(self.myLine.startPoint().pnt(), self.myArc)
     self.moveArc()
 
   def test_middle_point_coincidence_move_arc(self):
@@ -206,7 +206,7 @@ class TestMiddlePointOnArc(unittest.TestCase):
     self.mySketch.setMiddlePoint(self.myLine.startPoint(), self.myArc.results()[1])
     self.myDOF -= 2
     model.do()
-    self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+    self.checkMiddlePoint(self.myLine.startPoint().pnt(), self.myArc)
     self.moveArc()
 
   def test_middle_point_move_line(self):
@@ -215,7 +215,7 @@ class TestMiddlePointOnArc(unittest.TestCase):
     self.mySketch.setMiddlePoint(self.myLine.startPoint(), self.myArc.results()[1])
     self.myDOF -= 2
     model.do()
-    self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+    self.checkMiddlePoint(self.myLine.startPoint().pnt(), self.myArc)
     self.moveLine()
 
   def test_middle_point_coincidence_move_line(self):
@@ -226,7 +226,7 @@ class TestMiddlePointOnArc(unittest.TestCase):
     self.mySketch.setMiddlePoint(self.myLine.startPoint(), self.myArc.results()[1])
     self.myDOF -= 2
     model.do()
-    self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+    self.checkMiddlePoint(self.myLine.startPoint().pnt(), self.myArc)
     self.moveLine()
 
   def test_remove_middle_point(self):
@@ -236,7 +236,7 @@ class TestMiddlePointOnArc(unittest.TestCase):
     self.myDOF -= 2
     model.do()
     model.assertArcValidity(self.myArc)
-    self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+    self.checkMiddlePoint(self.myLine.startPoint().pnt(), self.myArc)
     self.checkDOF()
     # remove middle point
     self.myDocument.removeFeature(mp.feature())
@@ -246,6 +246,36 @@ class TestMiddlePointOnArc(unittest.TestCase):
     # set flag False to avoid checking middle point constraint in tearDown() method
     self.myTestPassed = False
 
+  def test_middle_point_by_object(self):
+    """ Test 11. Set middle point constraint on Arc
+    """
+    self.myArc = self.mySketch.addArc(6, 4, 15, 1, 14, 9, False)
+    self.mySketch.setFixed(self.myArc.center())
+    self.mySketch.setRadius(self.myArc.results()[1], 10)
+
+    SketchLine_2 = self.mySketch.addLine(6, 4, 16, 4)
+    SketchLine_2.setAuxiliary(True)
+    self.mySketch.setCoincident(self.myArc.center(), SketchLine_2.startPoint())
+    self.mySketch.setCoincident(self.myArc.startPoint(), SketchLine_2.endPoint())
+    self.mySketch.setHorizontal(SketchLine_2.result())
+
+    SketchLine_3 = self.mySketch.addLine(6, 4, 14.66025403784439, 9)
+    SketchLine_3.setAuxiliary(True)
+    self.mySketch.setCoincident(self.myArc.center(), SketchLine_3.startPoint())
+    self.mySketch.setCoincident(self.myArc.endPoint(), SketchLine_3.endPoint())
+
+    ### Create SketchConstraintAngle
+    self.mySketch.setAngle(SketchLine_2.result(), SketchLine_3.result(), 30, type = "Direct")
+
+    # Ajout d'un point auxiliaire au milieu
+    SketchPoint_02 = self.mySketch.setMiddlePoint(self.myArc.results()[1])
+    model.do()
+
+    aPoint = SketchPoint_02.coordinates().pnt()
+    self.checkMiddlePoint(aPoint, self.myArc)
+
+    # set flag False to avoid checking middle point constraint in tearDown() method
+    self.myTestPassed = False
 
 if __name__ == "__main__":
     test_program = unittest.main(exit=False)
index 794a7d37b80ccf4d7de68e083c886592f8b4802d..714f9e949a8498831b1e7d4dbc9329417bc8f786 100644 (file)
@@ -281,6 +281,59 @@ class TestMiddlePointOnEllipticArc(unittest.TestCase):
     # set flag False to avoid checking middle point constraint in tearDown() method
     self.myTestPassed = False
 
+  def test_middle_point_by_object(self):
+    """ Test 12. Set middle point constraint on elliptic arc
+    """
+
+    self.myArc = self.mySketch.addEllipticArc(26.13481199028052, 14.44743211950145, 27.10553481386106, 8.942189418241149, 30, 8.856406460551019, 22, 11, False)
+    [SketchPoint_1, SketchPoint_2, SketchPoint_3, SketchPoint_4, SketchPoint_5, SketchPoint_6, SketchPoint_7, SketchLine_4, SketchLine_5] = self.myArc.construction(center = "aux", firstFocus = "aux", secondFocus = "aux", majorAxisStart = "aux", majorAxisEnd = "aux", minorAxisStart = "aux", minorAxisEnd = "aux", majorAxis = "aux", minorAxis = "aux")
+    self.mySketch.setLength(SketchLine_5.result(), 10)
+    self.mySketch.setLength(SketchLine_4.result(), 15)
+
+    ### Create SketchProjection
+    SketchProjection_1 = self.mySketch.addProjection(model.selection("EDGE", "PartSet/OX"), False)
+    SketchLine_6 = SketchProjection_1.createdFeature()
+
+    ### Create SketchConstraintAngle
+    self.mySketch.setAngle(SketchLine_6.result(), SketchLine_5.result(), 10, type = "Direct")
+
+    ### Create SketchProjection
+    SketchProjection_2 = self.mySketch.addProjection(model.selection("EDGE", "PartSet/OX"), False)
+    SketchLine_7 = SketchProjection_2.createdFeature()
+
+    ### Create SketchLine
+    SketchLine_8 = self.mySketch.addLine(22, 11, 30, 8.856406460551019)
+    SketchLine_8.setAuxiliary(True)
+    self.mySketch.setCoincident(self.myArc.endPoint(), SketchLine_8.startPoint())
+    self.mySketch.setCoincident(self.myArc.startPoint(), SketchLine_8.endPoint())
+
+    ### Create SketchConstraintAngle
+    self.mySketch.setAngle(SketchLine_7.result(), SketchLine_8.result(), 15, type = "Direct")
+
+    ### Create SketchProjection
+    SketchProjection_3 = self.mySketch.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+    SketchPoint_8 = SketchProjection_3.createdFeature()
+    self.mySketch.setHorizontalDistance(SketchAPI_Point(SketchPoint_8).coordinates(), SketchLine_8.startPoint(), 22)
+
+    ### Create SketchProjection
+    SketchProjection_4 = self.mySketch.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+    SketchPoint_9 = SketchProjection_4.createdFeature()
+    self.mySketch.setVerticalDistance(SketchAPI_Point(SketchPoint_9).coordinates(), SketchLine_8.startPoint(), 11)
+
+    ### Create SketchProjection
+    SketchProjection_5 = self.mySketch.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+    SketchPoint_10 = SketchProjection_5.createdFeature()
+    self.mySketch.setHorizontalDistance(SketchAPI_Point(SketchPoint_10).coordinates(), SketchLine_8.endPoint(), 30)
+
+    # Create auxiliaire middle point
+    SketchPoint_03 = self.mySketch.setMiddlePoint(self.myArc.result())
+    model.do()
+
+    aPoint = SketchPoint_03.result().resultSubShapePair()[0].shape().vertex().point()
+    self.checkMiddlePoint(self.mySketch.to2D(aPoint), self.myArc)
+
+    # set flag False to avoid checking middle point constraint in tearDown() method
+    self.myTestPassed = False
 
 if __name__ == "__main__":
     test_program = unittest.main(exit=False)
index c6aa514e2162f2a5f6e64a280907e64eea3db8b2..b37468fc1206c69ea3a56f9f1d6cf22a4d3611be 100644 (file)
@@ -8,5 +8,8 @@ Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
 SketchCircle_1 = Sketch_1.addCircle(16, 54, 10)
 SketchLine_1 = Sketch_1.addLine(10, 10, 80, 80)
 SketchConstraintMiddle_1 = Sketch_1.setMiddlePoint(SketchCircle_1.center(), SketchLine_1.result())
+
+SketchLine_2 = Sketch_1.addLine(20, 10, 90, 80)
+SketchPoint_01 = Sketch_1.setMiddlePoint(SketchLine_2.result())
 model.do()
 model.end()
diff --git a/src/SketchPlugin/doc/images/MiddlePoint_obj.png b/src/SketchPlugin/doc/images/MiddlePoint_obj.png
new file mode 100644 (file)
index 0000000..af12521
Binary files /dev/null and b/src/SketchPlugin/doc/images/MiddlePoint_obj.png differ
diff --git a/src/SketchPlugin/doc/images/Middlepoint_obj_panel.png b/src/SketchPlugin/doc/images/Middlepoint_obj_panel.png
new file mode 100644 (file)
index 0000000..1254bcc
Binary files /dev/null and b/src/SketchPlugin/doc/images/Middlepoint_obj_panel.png differ
diff --git a/src/SketchPlugin/doc/images/Middlepoint_obj_point_panel.png b/src/SketchPlugin/doc/images/Middlepoint_obj_point_panel.png
new file mode 100644 (file)
index 0000000..762dd99
Binary files /dev/null and b/src/SketchPlugin/doc/images/Middlepoint_obj_point_panel.png differ
diff --git a/src/SketchPlugin/doc/images/Middlepoint_obj_point_res.png b/src/SketchPlugin/doc/images/Middlepoint_obj_point_res.png
new file mode 100644 (file)
index 0000000..8eed330
Binary files /dev/null and b/src/SketchPlugin/doc/images/Middlepoint_obj_point_res.png differ
diff --git a/src/SketchPlugin/doc/images/Middlepoint_obj_res.png b/src/SketchPlugin/doc/images/Middlepoint_obj_res.png
new file mode 100644 (file)
index 0000000..d46c16d
Binary files /dev/null and b/src/SketchPlugin/doc/images/Middlepoint_obj_res.png differ
diff --git a/src/SketchPlugin/doc/images/Middlepoint_panel.png b/src/SketchPlugin/doc/images/Middlepoint_panel.png
deleted file mode 100644 (file)
index ea30695..0000000
Binary files a/src/SketchPlugin/doc/images/Middlepoint_panel.png and /dev/null differ
diff --git a/src/SketchPlugin/doc/images/Middlepoint_res.png b/src/SketchPlugin/doc/images/Middlepoint_res.png
deleted file mode 100644 (file)
index 8eed330..0000000
Binary files a/src/SketchPlugin/doc/images/Middlepoint_res.png and /dev/null differ
index f39a348793e2a52203d9b6d759a399aab37b534a..a6d0142f81a810bb34152d9c8551e108e2a11abe 100644 (file)
@@ -10,9 +10,27 @@ To create a Middle point in the active Sketch:
 #. select in the Main Menu *Sketch - > Middle point* item  or
 #. click |middlepoint.icon| **Middle point** button in Sketch toolbar:
 
+There are 2 algorithms for creation of a middle constraint:
+
+.. figure:: images/MiddlePoint.png
+   :align: left
+   :height: 24px
+
+**By object and point** create a middle constraint by object (segment or arc) and point
+
+.. figure:: images/MiddlePoint_obj.png
+   :align: left
+   :height: 24px
+
+**By object** create a middle point on the object (segment or arc)
+
+-------------------------------------------------------------------------------------------
+
+By object and point
+""""""""""""""""""""""""""
 Property panel:
 
-.. figure:: images/Middlepoint_panel.png
+.. figure:: images/Middlepoint_obj_point_panel.png
    :align: center
 
 Input fields:
@@ -38,7 +56,38 @@ Result
 
 Created Middle point constraint appears in the view.
 
-.. figure:: images/Middlepoint_res.png
+.. figure:: images/Middlepoint_obj_point_res.png
+   :align: center
+
+   Created middle point constraint
+
+By object
+""""""""""""""""""""""""""
+Property panel:
+
+.. figure:: images/Middlepoint_obj_panel.png
+   :align: center
+
+Input fields:
+
+- **Object** is a line selected in the view.
+
+| After the object are selected, will be created auxiliary point on the middle of the line.
+| The middle points are marked with a special sign.
+
+**TUI Command**:
+
+.. py:function:: SketchPoint_1 = Sketch_1.setMiddlePoint(Line)
+
+    :param object: A line.
+    :return: Created middle point.
+
+Result
+""""""
+
+Created Middle point constraint appears in the view.
+
+.. figure:: images/Middlepoint_obj_res.png
    :align: center
 
    Created middle point constraint
diff --git a/src/SketchPlugin/icons/middlepoint_obj.png b/src/SketchPlugin/icons/middlepoint_obj.png
new file mode 100644 (file)
index 0000000..af12521
Binary files /dev/null and b/src/SketchPlugin/icons/middlepoint_obj.png differ
index 6f665a49e1749ac83761fec2eb1d94beddc474ed..f69c000407226b8282d0d5d588caeadb0b69c460 100644 (file)
       <feature id="SketchConstraintMiddle" title="Middle point" tooltip="Create constraint for setting middle point on a line"
                icon="icons/Sketch/middlepoint.png"
                helpfile="middleFeature.html">
-        <sketch_shape_selector id="ConstraintEntityA" label="First object" tooltip="Select a first object" shape_types="vertex edge">
-          <validator id="PartSet_DifferentObjects"/>
-          <validator id="SketchPlugin_ExternalValidator" parameters="ConstraintEntityB"/>
-          <validator id="SketchPlugin_MiddlePointAttr" parameters="ConstraintEntityB"/>
-        </sketch_shape_selector>
-        <sketch_shape_selector id="ConstraintEntityB" label="Second object" tooltip="Select a second object" shape_types="vertex edge">
-          <validator id="PartSet_DifferentObjects"/>
-          <validator id="SketchPlugin_ExternalValidator" parameters="ConstraintEntityA"/>
-          <validator id="SketchPlugin_MiddlePointAttr" parameters="ConstraintEntityA"/>
-        </sketch_shape_selector>
+        <toolbox id="middle_type">
+          <box id="middle_type_by_line_and_point"
+               icon="icons/Sketch/middlepoint.png"
+               title="Line and point">
+            <sketch_shape_selector id="ConstraintEntityA"
+                            label="First object"
+                            tooltip="Select a first object"
+                            shape_types="vertex edge"
+                            use_external="true">
+              <validator id="SketchPlugin_ExternalValidator" parameters="ConstraintEntityB"/>
+              <validator id="SketchPlugin_MiddlePointAttr" parameters="ConstraintEntityB"/>
+            </sketch_shape_selector>
+            <sketch_shape_selector id="ConstraintEntityB"
+                  label="Second object"
+                  tooltip="Select a second object"
+                  shape_types="vertex edge"
+                  use_external="true">
+              <validator id="SketchPlugin_ExternalValidator" parameters="ConstraintEntityA"/>
+              <validator id="SketchPlugin_MiddlePointAttr" parameters="ConstraintEntityA"/>
+            </sketch_shape_selector>
+          </box>
+          <box id="middle_type_by_line"
+               icon="icons/Sketch/middlepoint_obj.png"
+               title="Line">
+            <sketch_shape_selector id="ConstraintEntityA"
+             label="Object"
+             tooltip="Select a first object"
+             shape_types="edge"
+             use_external="true">
+            </sketch_shape_selector>
+          </box>
+        </toolbox>
         <validator id="PartSet_MiddlePointSelection"/>
       </feature>
 
index ab382114e65799f92e7002d125de1ee7dc11df1f..1f0fd0e7c6d34ec09bc6f7b6bbe845a17d878cd1 100644 (file)
@@ -527,7 +527,6 @@ bool PlaneGCSSolver_Tools::isAttributeApplicable(const std::string& theAttrName,
            theAttrName == SketchPlugin_BSplinePeriodic::MULTS_ID() ||
            theAttrName == SketchPlugin_BSplinePeriodic::DEGREE_ID();
   }
-
   // suppose that all remaining features are points
   return theAttrName == SketchPlugin_Point::COORD_ID();
 }