]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Implement constraint middle-point-on-line
authorazv <azv@opencascade.com>
Fri, 29 Jan 2016 08:40:07 +0000 (11:40 +0300)
committerdbv <dbv@opencascade.com>
Tue, 16 Feb 2016 14:04:32 +0000 (17:04 +0300)
17 files changed:
src/PartSet/PartSet_Module.cpp
src/PartSet/PartSet_Validators.cpp
src/PartSet/PartSet_Validators.h
src/PartSet/PartSet_icons.qrc
src/PartSet/icons/middlepoint.png [new file with mode: 0644]
src/SketchPlugin/CMakeLists.txt
src/SketchPlugin/SketchPlugin_ConstraintMiddle.cpp [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_ConstraintMiddle.h [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_Plugin.cpp
src/SketchPlugin/SketchPlugin_Validators.cpp
src/SketchPlugin/SketchPlugin_Validators.h
src/SketchPlugin/Test/TestConstraintMiddlePoint.py [new file with mode: 0644]
src/SketchPlugin/plugin-Sketch.xml
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.cpp
src/SketchSolver/SketchSolver_Constraint.cpp
src/SketchSolver/SketchSolver_IConstraintWrapper.h
src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ConstraintType.h

index 124766058ad16f32fe557039438a8bd52a973703..35a07704158cb12a36619794de2eec6ba2be13d2 100755 (executable)
@@ -203,6 +203,7 @@ void PartSet_Module::registerValidators()
   aFactory->registerValidator("PartSet_AngleSelection", new PartSet_AngleSelection);
   aFactory->registerValidator("PartSet_EqualSelection", new PartSet_EqualSelection);
   aFactory->registerValidator("PartSet_CollinearSelection", new PartSet_CollinearSelection);
+  aFactory->registerValidator("PartSet_MiddlePointSelection", new PartSet_MiddlePointSelection);
   aFactory->registerValidator("PartSet_DifferentObjects", new PartSet_DifferentObjectsValidator);
   aFactory->registerValidator("PartSet_CoincidentAttr", new PartSet_CoincidentAttr);
   aFactory->registerValidator("PartSet_SketchEntityValidator", new PartSet_SketchEntityValidator);
index a81557ac4b05a6e3c8bddb48c321a4b849b17ab0..163063bd0b514ba46ac4bb844ae5dc0701230762 100755 (executable)
@@ -324,6 +324,14 @@ bool PartSet_CollinearSelection::isValid(const ModuleBase_ISelection* theSelecti
   }
 }
 
+bool PartSet_MiddlePointSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
+{
+  if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0)
+    return isEmptySelectionValid(theOperation);
+  else
+    return shapesNbLines(theSelection) == 1 && shapesNbPoints(theSelection) == 1;
+}
+
 
 std::string PartSet_DifferentObjectsValidator::errorMessage(
                          const PartSet_DifferentObjectsValidator::ErrorType& theType,
index 05e90f05f6302232dc859842752cffdafaad9ada..aaf3c88c942c634c3cf33fa768b0f0b29aa79478 100644 (file)
@@ -123,6 +123,14 @@ public:
   PARTSET_EXPORT virtual bool isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const;
 };
 
+//! \ingroup Validators
+//! A class to validate a selection for Middle point constraints operation
+class PartSet_MiddlePointSelection : public ModuleBase_SelectionValidator
+{
+public:
+  PARTSET_EXPORT virtual bool isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const;
+};
+
 ////////////// Attribute validators ////////////////
 
 
index 9b674aea94604e648a6530d59fd8a4a811b300af..826d7fd117098817440528f42363ea8dc7bfd29e 100644 (file)
@@ -83,5 +83,6 @@
      <file>icons/bool_common.png</file>
      <file>icons/plane_view.png</file>
      <file>icons/collinear.png</file>
+     <file>icons/middlepoint.png</file>
  </qresource>
  </RCC>
diff --git a/src/PartSet/icons/middlepoint.png b/src/PartSet/icons/middlepoint.png
new file mode 100644 (file)
index 0000000..98d1b63
Binary files /dev/null and b/src/PartSet/icons/middlepoint.png differ
index a44cf0623a6d347a9cb28a5f85b9f5d9b020f565..bf05209c40618ab691d1ca182b2eeafe4281f040 100644 (file)
@@ -19,6 +19,7 @@ SET(PROJECT_HEADERS
     SketchPlugin_ConstraintCollinear.h
     SketchPlugin_ConstraintDistance.h
     SketchPlugin_ConstraintLength.h
+    SketchPlugin_ConstraintMiddle.h
     SketchPlugin_ConstraintParallel.h
     SketchPlugin_ConstraintPerpendicular.h
     SketchPlugin_ConstraintRadius.h
@@ -52,6 +53,7 @@ SET(PROJECT_SOURCES
     SketchPlugin_ConstraintCollinear.cpp
     SketchPlugin_ConstraintDistance.cpp
     SketchPlugin_ConstraintLength.cpp
+    SketchPlugin_ConstraintMiddle.cpp
     SketchPlugin_ConstraintParallel.cpp
     SketchPlugin_ConstraintPerpendicular.cpp
     SketchPlugin_ConstraintRadius.cpp
@@ -116,6 +118,7 @@ ADD_UNIT_TESTS(TestSketchPointLine.py
                TestConstraintTangent.py
                TestConstraintMirror.py
                TestConstraintAngle.py
+               TestConstraintMiddlePoint.py
                TestMultiRotation.py
                TestMultiTranslation.py
                TestFillet.py
diff --git a/src/SketchPlugin/SketchPlugin_ConstraintMiddle.cpp b/src/SketchPlugin/SketchPlugin_ConstraintMiddle.cpp
new file mode 100644 (file)
index 0000000..76e8509
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
+
+// File:    SketchPlugin_ConstraintMiddle.cpp
+// Created: 26 May 2014
+// Author:  Artem ZHIDKOV
+
+#include "SketchPlugin_ConstraintMiddle.h"
+
+SketchPlugin_ConstraintMiddle::SketchPlugin_ConstraintMiddle()
+{
+}
+
+void SketchPlugin_ConstraintMiddle::initAttributes()
+{
+  data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
+  data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
+}
+
+void SketchPlugin_ConstraintMiddle::execute()
+{
+}
+
+AISObjectPtr SketchPlugin_ConstraintMiddle::getAISObject(AISObjectPtr thePrevious)
+{
+  if (!sketch())
+    return thePrevious;
+
+  AISObjectPtr anAIS = thePrevious;
+  if (!anAIS) {
+    // TODO
+    //anAIS = SketcherPrs_Factory::collinearConstraint(this, sketch()->coordinatePlane());
+  }
+  return anAIS;
+}
+
+
diff --git a/src/SketchPlugin/SketchPlugin_ConstraintMiddle.h b/src/SketchPlugin/SketchPlugin_ConstraintMiddle.h
new file mode 100644 (file)
index 0000000..9cf7b86
--- /dev/null
@@ -0,0 +1,50 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
+
+// File:    SketchPlugin_ConstraintMiddle.h
+// Created: 27 Jan 2016
+// Author:  Artem ZHIDKOV
+
+#ifndef SketchPlugin_ConstraintMiddle_H_
+#define SketchPlugin_ConstraintMiddle_H_
+
+#include "SketchPlugin.h"
+#include <SketchPlugin_Sketch.h>
+#include "SketchPlugin_ConstraintBase.h"
+
+/** \class SketchPlugin_ConstraintMiddle
+ *  \ingroup Plugins
+ *  \brief Feature for creation of a new constraintwhich places a point in the middle of a line
+ *
+ *  This constraint has two attributes:
+ *  SketchPlugin_Constraint::ENTITY_A() and SketchPlugin_Constraint::ENTITY_B()
+ */
+class SketchPlugin_ConstraintMiddle : public SketchPlugin_ConstraintBase
+{
+ public:
+  /// Parallel constraint kind
+  inline static const std::string& ID()
+  {
+    static const std::string MY_CONSTRAINT_MIDDLE_ID("SketchConstraintMiddle");
+    return MY_CONSTRAINT_MIDDLE_ID;
+  }
+  /// \brief Returns the kind of a feature
+  SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
+  {
+    static std::string MY_KIND = SketchPlugin_ConstraintMiddle::ID();
+    return MY_KIND;
+  }
+
+  /// \brief Creates a new part document if needed
+  SKETCHPLUGIN_EXPORT virtual void execute();
+
+  /// \brief Request for initialization of data model of the feature: adding all attributes
+  SKETCHPLUGIN_EXPORT virtual void initAttributes();
+
+  /// Returns the AIS preview
+  SKETCHPLUGIN_EXPORT virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious);
+
+  /// \brief Use plugin manager for features creation
+  SketchPlugin_ConstraintMiddle();
+};
+
+#endif
index 0119d3b633ead0527249ba168aaca5ecc1f1c3a3..a07675a5399bd9ad736d020b0f81c513ad5874ea 100644 (file)
@@ -14,6 +14,7 @@
 #include <SketchPlugin_ConstraintFillet.h>
 #include <SketchPlugin_ConstraintHorizontal.h>
 #include <SketchPlugin_ConstraintLength.h>
+#include <SketchPlugin_ConstraintMiddle.h>
 #include <SketchPlugin_ConstraintMirror.h>
 #include <SketchPlugin_ConstraintParallel.h>
 #include <SketchPlugin_ConstraintPerpendicular.h>
@@ -73,6 +74,8 @@ SketchPlugin_Plugin::SketchPlugin_Plugin()
                               new SketchPlugin_SolverErrorValidator);
   aFactory->registerValidator("SketchPlugin_FilletVertexValidator",
                               new SketchPlugin_FilletVertexValidator);
+  aFactory->registerValidator("SketchPlugin_MiddlePointAttr",
+                              new SketchPlugin_MiddlePointAttrValidator);
 
   // register this plugin
   ModelAPI_Session::get()->registerPlugin(this);
@@ -136,6 +139,8 @@ FeaturePtr SketchPlugin_Plugin::createFeature(string theFeatureID)
     return FeaturePtr(new SketchPlugin_ConstraintEqual);
   } else if (theFeatureID == SketchPlugin_ConstraintTangent::ID()) {
     return FeaturePtr(new SketchPlugin_ConstraintTangent);
+  } else if (theFeatureID == SketchPlugin_ConstraintMiddle::ID()) {
+    return FeaturePtr(new SketchPlugin_ConstraintMiddle);
   } else if (theFeatureID == SketchPlugin_ConstraintMirror::ID()) {
     return FeaturePtr(new SketchPlugin_ConstraintMirror);
   } else if (theFeatureID == SketchPlugin_ConstraintFillet::ID()) {
index 66fc18d8b5ea5f3ef0063e3961473ad084dbf172..612b083e76516959b6dfe77989ddecd96f2f1e40 100755 (executable)
@@ -615,3 +615,49 @@ bool SketchPlugin_FilletVertexValidator::isValid(const AttributePtr& theAttribut
 
   return true;
 }
+
+bool SketchPlugin_MiddlePointAttrValidator::isValid(const AttributePtr& theAttribute, 
+                                                    const std::list<std::string>& theArguments,
+                                                    std::string& theError) const
+{
+  if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
+    theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
+    return false;
+  }
+
+  // there is a check whether the feature contains a point and a linear edge or two point values
+  std::string aParamA = theArguments.front();
+  SessionPtr aMgr = ModelAPI_Session::get();
+  ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
+
+  FeaturePtr anAttributeFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
+  AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
+  AttributeRefAttrPtr anOtherAttr = anAttributeFeature->data()->refattr(aParamA);
+
+  AttributeRefAttrPtr aRefAttrs[2] = {aRefAttr, anOtherAttr};
+  int aNbPoints = 0;
+  int aNbLines = 0;
+  for (int i = 0; i < 2; ++i) {
+    if (!aRefAttrs[i]->isObject())
+      ++aNbPoints;
+    else {
+      FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrs[i]->object());
+      if (!aFeature) {
+        if (aNbPoints + aNbLines != 0)
+          return true;
+        else continue;
+      }
+
+      if (aFeature->getKind() == SketchPlugin_Point::ID())
+        ++aNbPoints;
+      else if (aFeature->getKind() == SketchPlugin_Line::ID())
+        ++aNbLines;
+    }
+  }
+
+  if (aNbPoints != 1 || aNbLines != 1) {
+    theError = "Middle point constraint allows points and lines only";
+    return false;
+  }
+  return true;
+}
index 966f33be1bd1533f746c112f85bcec4abd1c5054..1b38eb0e7b2dee8afc9648246c42094d9cff5cd1 100644 (file)
@@ -180,4 +180,23 @@ class SketchPlugin_FilletVertexValidator : public ModelAPI_AttributeValidator
                        std::string& theError) const;
 };
 
+
+/**\class SketchPlugin_MiddlePointAttrValidator
+ * \ingroup Validators
+ * \brief Validator for the middle point constraint input.
+ *
+ * It checks that attributes of the Middle point constraint are correct.
+ */
+class SketchPlugin_MiddlePointAttrValidator : public ModelAPI_AttributeValidator
+{
+ public:
+  //! returns true if attribute is valid
+  //! \param theAttribute the checked attribute
+  //! \param theArguments arguments of the attribute (not used)
+  //! \param theError error message
+  virtual bool isValid(const AttributePtr& theAttribute,
+                       const std::list<std::string>& theArguments,
+                       std::string& theError) const;
+};
+
 #endif
diff --git a/src/SketchPlugin/Test/TestConstraintMiddlePoint.py b/src/SketchPlugin/Test/TestConstraintMiddlePoint.py
new file mode 100644 (file)
index 0000000..0950608
--- /dev/null
@@ -0,0 +1,141 @@
+"""
+    TestConstraintCoincidence.py
+    Unit test of SketchPlugin_ConstraintCoincidence class
+    
+    SketchPlugin_Constraint
+        static const std::string MY_CONSTRAINT_VALUE("ConstraintValue");
+        static const std::string MY_FLYOUT_VALUE_PNT("ConstraintFlyoutValuePnt");
+        static const std::string MY_ENTITY_A("ConstraintEntityA");
+        static const std::string MY_ENTITY_B("ConstraintEntityB");
+        static const std::string MY_ENTITY_C("ConstraintEntityC");
+        static const std::string MY_ENTITY_D("ConstraintEntityD");
+        
+    SketchPlugin_ConstraintCoincidence
+        static const std::string MY_CONSTRAINT_COINCIDENCE_ID("SketchConstraintCoincidence");
+        data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
+        data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
+
+"""
+from GeomDataAPI import *
+from ModelAPI import *
+import math
+#=========================================================================
+# Initialization of the test
+#=========================================================================
+
+__updated__ = "2016-01-29"
+TOLERANCE = 1.e-7
+
+
+#=========================================================================
+# Auxiliary functions
+#=========================================================================
+def checkMiddlePoint(point, line):
+    aStart = geomDataAPI_Point2D(line.attribute("StartPoint"))
+    aEnd   = geomDataAPI_Point2D(line.attribute("EndPoint"))
+    assert math.fabs(aStart.x() + aEnd.x() - 2.0 * point.x()) <= TOLERANCE, "x1={0}, x2={1}, mid={2}".format(aStart.x(), aEnd.x(), point.x())
+    assert math.fabs(aStart.y() + aEnd.y() - 2.0 * point.y()) <= TOLERANCE, "y1={0}, y2={1}, mid={2}".format(aStart.y(), aEnd.y(), point.y())
+
+
+#=========================================================================
+# Start of test
+#=========================================================================
+aSession = ModelAPI_Session.get()
+aDocument = aSession.moduleDocument()
+# add an origin
+aSession.startOperation()
+aFeature = aDocument.addFeature("Point")
+aFeature.real("x").setValue(0.)
+aFeature.real("y").setValue(0.)
+aFeature.real("z").setValue(0.)
+anOriginName = aFeature.name()
+aSession.finishOperation()
+#=========================================================================
+# Creation of a sketch
+#=========================================================================
+aSession.startOperation()
+aSketchFeature = featureToCompositeFeature(aDocument.addFeature("Sketch"))
+origin = geomDataAPI_Point(aSketchFeature.attribute("Origin"))
+origin.setValue(0, 0, 0)
+dirx = geomDataAPI_Dir(aSketchFeature.attribute("DirX"))
+dirx.setValue(1, 0, 0)
+norm = geomDataAPI_Dir(aSketchFeature.attribute("Norm"))
+norm.setValue(0, 0, 1)
+aSession.finishOperation()
+#=========================================================================
+# Create a two lines
+#=========================================================================
+aSession.startOperation()
+aLine1 = aSketchFeature.addFeature("SketchLine")
+aStartPoint1 = geomDataAPI_Point2D(aLine1.attribute("StartPoint"))
+aEndPoint1 = geomDataAPI_Point2D(aLine1.attribute("EndPoint"))
+aStartPoint1.setValue(50., 0.)
+aEndPoint1.setValue(100., 25.)
+aLine2 = aSketchFeature.addFeature("SketchLine")
+aStartPoint2 = geomDataAPI_Point2D(aLine2.attribute("StartPoint"))
+aEndPoint2 = geomDataAPI_Point2D(aLine2.attribute("EndPoint"))
+aStartPoint2.setValue(10., 100.)
+aEndPoint2.setValue(100., 25.)
+aSession.finishOperation()
+#=========================================================================
+# Make end point of second line middle point on first line
+#=========================================================================
+aSession.startOperation()
+aConstraint = aSketchFeature.addFeature("SketchConstraintMiddle")
+reflistA = aConstraint.refattr("ConstraintEntityA")
+reflistB = aConstraint.refattr("ConstraintEntityB")
+reflistA.setAttr(aEndPoint2)
+reflistB.setObject(aLine1.lastResult())
+aConstraint.execute()
+aSession.finishOperation()
+#=========================================================================
+# Check values and move one constrainted object
+#=========================================================================
+checkMiddlePoint(aEndPoint2, aLine1)
+deltaX, deltaY = -80.0, -40.0
+aSession.startOperation()
+aStartPoint1.setValue(aStartPoint1.x() + deltaX, aStartPoint1.y() + deltaY)
+aSession.finishOperation()
+checkMiddlePoint(aEndPoint2, aLine1)
+#=========================================================================
+# Remove constraint and move the line
+#=========================================================================
+aCurX, aCurY = aEndPoint2.x(), aEndPoint2.y()
+aSession.startOperation()
+aDocument.removeFeature(aConstraint)
+aSession.finishOperation()
+aSession.startOperation()
+aEndPoint1.setValue(90., 0.)
+aSession.finishOperation()
+assert (aEndPoint2.x() == aCurX and aEndPoint2.y() == aCurY)
+
+#=========================================================================
+# Set external point as a middle point
+#=========================================================================
+# create origin
+aSession.startOperation()
+anOrigRes = modelAPI_Result(aDocument.objectByName("Construction", anOriginName))
+assert (anOrigRes)
+anOrigShape = anOrigRes.shape()
+assert (anOrigShape)
+anOrigin = aSketchFeature.addFeature("SketchPoint")
+anOriginCoord = geomDataAPI_Point2D(anOrigin.attribute("PointCoordindates"))
+anOriginCoord.setValue(0., 0.)
+anOrigin.selection("External").setValue(anOrigRes, anOrigShape)
+aSession.finishOperation()
+# middle point constraint
+aSession.startOperation()
+aConstraint = aSketchFeature.addFeature("SketchConstraintMiddle")
+reflistA = aConstraint.refattr("ConstraintEntityA")
+reflistB = aConstraint.refattr("ConstraintEntityB")
+reflistA.setObject(aLine2.lastResult())
+reflistB.setObject(anOrigin.lastResult())
+aSession.finishOperation()
+checkMiddlePoint(anOriginCoord, aLine2)
+#=========================================================================
+# Check origin coordinates does not changed
+#=========================================================================
+assert (anOriginCoord.x() == 0. and anOriginCoord.y() == 0.)
+#=========================================================================
+# End of test
+#=========================================================================
index 6b7233f6ce54e62dd12df17a891a4fc9c0d58091..79de2c5d7002c02a490d7089eed9b1ba8e7b6769 100644 (file)
@@ -5,7 +5,7 @@
     <group id="Basic">
       <feature
         id="Sketch"
-        nested="SketchPoint SketchLine SketchCircle SketchArc SketchConstraintLength SketchConstraintRadius SketchConstraintDistance SketchConstraintParallel SketchConstraintPerpendicular SketchConstraintRigid SketchConstraintHorizontal SketchConstraintVertical SketchConstraintEqual SketchConstraintTangent SketchConstraintFillet SketchConstraintCoincidence SketchConstraintMirror SketchConstraintAngle SketchMultiRotation SketchMultiTranslation SketchConstraintCollinear"
+        nested="SketchPoint SketchLine SketchCircle SketchArc SketchConstraintLength SketchConstraintRadius SketchConstraintDistance SketchConstraintParallel SketchConstraintPerpendicular SketchConstraintRigid SketchConstraintHorizontal SketchConstraintVertical SketchConstraintEqual SketchConstraintTangent SketchConstraintFillet SketchConstraintCoincidence SketchConstraintMirror SketchConstraintAngle SketchMultiRotation SketchMultiTranslation SketchConstraintCollinear SketchConstraintMiddle"
         when_nested="accept abort"
         title="Sketch"
         tooltip="Create sketch"
         </sketch_shape_selector>
         <validator id="PartSet_CollinearSelection"/>
       </feature>
+
+      <!--  SketchConstraintMiddle  -->
+      <feature id="SketchConstraintMiddle" title="Middle point" tooltip="Create constraint for setting middle point on a line" icon=":icons/middlepoint.png">
+        <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>
+        <validator id="PartSet_MiddlePointSelection"/>
+      </feature>
          
     </group>
     
index 9cc222f580223ed0cbb50e33ac7787ae8e8305eb..23933b232d6ee48c19872ca21ea23b4be62bc350 100644 (file)
@@ -133,6 +133,11 @@ static ConstraintWrapperPtr
                            const GroupID& theGroupID,
                            std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity1,
                            std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity2);
+static ConstraintWrapperPtr
+  createConstraintMiddlePoint(ConstraintPtr theConstraint,
+                              const GroupID& theGroupID,
+                              std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint,
+                              std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity);
 
 
 
@@ -203,6 +208,10 @@ std::list<ConstraintWrapperPtr> PlaneGCSSolver_Builder::createConstraint(
     aResult = createConstraintPointOnEntity(theConstraint, theGroupID, theType,
                   aPoint1, GCS_ENTITY_WRAPPER(theEntity1));
     break;
+  case CONSTRAINT_MIDDLE_POINT:
+    aResult = createConstraintMiddlePoint(theConstraint, theGroupID,
+                  aPoint1, GCS_ENTITY_WRAPPER(theEntity1));
+    break;
   case CONSTRAINT_PT_PT_DISTANCE:
     aResult = createConstraintDistancePointPoint(theConstraint, theGroupID,
                   GCS_PARAMETER_WRAPPER(createParameter(GID_OUTOFGROUP, theValue)),
@@ -816,6 +825,65 @@ ConstraintWrapperPtr createConstraintPointOnEntity(
   return aResult;
 }
 
+// calculate length of the line
+static inline double lineLength(const GCS::Line& theLine)
+{
+  double aDir[2] = {*(theLine.p2.x) - *(theLine.p1.x), *(theLine.p2.y) - *(theLine.p1.y)};
+  return sqrt(aDir[0] * aDir[0] + aDir[1] * aDir[1]);
+}
+
+// check the point is on the line
+static inline bool isPointOnLine(const GCS::Point& thePoint, const GCS::Line& theLine)
+{
+  double aDir[2] = {*(theLine.p2.x) - *(theLine.p1.x), *(theLine.p2.y) - *(theLine.p1.y)};
+  double aVec[2] = {*(thePoint.x) - *(theLine.p1.x), *(thePoint.y) - *(theLine.p1.y)};
+  double aCross = aVec[0] * aDir[1] - aVec[1] * aDir[0];
+  return fabs(aCross) < tolerance;
+}
+
+ConstraintWrapperPtr createConstraintMiddlePoint(
+    ConstraintPtr theConstraint,
+    const GroupID& theGroupID,
+    std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint,
+    std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity)
+{
+  GCSPointPtr aPoint = thePoint->point();
+  std::shared_ptr<GCS::Line> aLine = std::dynamic_pointer_cast<GCS::Line>(theEntity->entity());
+  if (!aLine)
+    return ConstraintWrapperPtr();
+
+  std::list<GCSConstraintPtr> aConstrList;
+  aConstrList.push_back(GCSConstraintPtr(new GCS::ConstraintPointOnLine(*aPoint, *aLine)));
+  double aDist = lineLength(*aLine);
+  std::shared_ptr<PlaneGCSSolver_ParameterWrapper> aDistance =
+      std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(createParameter(theGroupID, aDist));
+  aConstrList.push_back(GCSConstraintPtr(
+      new GCS::ConstraintP2PDistance(*aPoint, aLine->p1, aDistance->parameter())));
+  aConstrList.push_back(GCSConstraintPtr(
+      new GCS::ConstraintP2PDistance(*aPoint, aLine->p2, aDistance->parameter())));
+
+  // Workaround to avoid conflicting constraints when the point is already placed on line
+  if (thePoint->group() != GID_UNKNOWN && isPointOnLine(*aPoint, *aLine)) {
+    std::shared_ptr<GeomDataAPI_Point2D> aCoord =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(thePoint->baseAttribute());
+    if (aCoord) {
+      *(aPoint->x) = (*(aLine->p1.x) + *(aLine->p2.x)) * 0.5;
+      *(aPoint->y) = (*(aLine->p1.y) + *(aLine->p2.y)) * 0.5;
+      aCoord->setValue(*(aPoint->x), *(aPoint->y));
+    }
+  }
+
+  std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aResult(new PlaneGCSSolver_ConstraintWrapper(
+      theConstraint, aConstrList, CONSTRAINT_MIDDLE_POINT));
+  aResult->setGroup(theGroupID);
+  std::list<EntityWrapperPtr> aSubs(1, thePoint);
+  aSubs.push_back(theEntity);
+  aResult->setEntities(aSubs);
+  aResult->setValueParameter(aDistance);
+  return aResult;
+}
+
+
 ConstraintWrapperPtr createConstraintDistancePointPoint(
     ConstraintPtr theConstraint,
     const GroupID& theGroupID,
index 47ec0fdb3beb37bb8cfa6853c2f0007b09064771..1d765142e4fee658c7a4953ef5ad680fc80e88d3 100644 (file)
@@ -15,6 +15,7 @@
 #include <SketchPlugin_ConstraintEqual.h>
 #include <SketchPlugin_ConstraintHorizontal.h>
 #include <SketchPlugin_ConstraintLength.h>
+#include <SketchPlugin_ConstraintMiddle.h>
 #include <SketchPlugin_ConstraintMirror.h>
 #include <SketchPlugin_ConstraintParallel.h>
 #include <SketchPlugin_ConstraintPerpendicular.h>
@@ -82,6 +83,8 @@ SketchSolver_ConstraintType SketchSolver_Constraint::TYPE(ConstraintPtr theConst
     return CONSTRAINT_TANGENT;
   else if (aType == SketchPlugin_ConstraintCollinear::ID())
     return CONSTRAINT_COLLINEAR;
+  else if (aType == SketchPlugin_ConstraintMiddle::ID())
+    return CONSTRAINT_MIDDLE_POINT;
   return CONSTRAINT_UNKNOWN;
 }
 
index fcd0c597a3bb8c41e7e09ab2940960695d6c804d..12bf834230261837c64ada37ec8be8470e14392d 100644 (file)
@@ -21,6 +21,7 @@ enum SketchSolver_ConstraintType {
   CONSTRAINT_PT_PT_COINCIDENT,
   CONSTRAINT_PT_ON_LINE,
   CONSTRAINT_PT_ON_CIRCLE,
+  CONSTRAINT_MIDDLE_POINT,
   CONSTRAINT_DISTANCE,         // base distance if we don't know the measured objects yet
   CONSTRAINT_PT_PT_DISTANCE,
   CONSTRAINT_PT_LINE_DISTANCE,
index a38939bd415378dbacb5ba3ea6bbe76dcb60c58d..14ecf3adc4528f8504489782b002c50aeb2fec09 100644 (file)
@@ -19,6 +19,7 @@ namespace ConstraintType
     case CONSTRAINT_PT_PT_COINCIDENT:   return SLVS_C_POINTS_COINCIDENT;
     case CONSTRAINT_PT_ON_LINE:         return SLVS_C_PT_ON_LINE;
     case CONSTRAINT_PT_ON_CIRCLE:       return SLVS_C_PT_ON_CIRCLE;
+    case CONSTRAINT_MIDDLE_POINT:       return SLVS_C_AT_MIDPOINT;
     case CONSTRAINT_PT_PT_DISTANCE:     return SLVS_C_PT_PT_DISTANCE;
     case CONSTRAINT_PT_LINE_DISTANCE:   return SLVS_C_PT_LINE_DISTANCE;
     case CONSTRAINT_ANGLE:              return SLVS_C_ANGLE;
@@ -48,6 +49,7 @@ namespace ConstraintType
     case SLVS_C_POINTS_COINCIDENT:    return CONSTRAINT_PT_PT_COINCIDENT;
     case SLVS_C_PT_ON_LINE:           return CONSTRAINT_PT_ON_LINE;
     case SLVS_C_PT_ON_CIRCLE:         return CONSTRAINT_PT_ON_CIRCLE;
+    case SLVS_C_AT_MIDPOINT:          return CONSTRAINT_MIDDLE_POINT;
     case SLVS_C_PT_PT_DISTANCE:       return CONSTRAINT_PT_PT_DISTANCE;
     case SLVS_C_PT_LINE_DISTANCE:     return CONSTRAINT_PT_LINE_DISTANCE;
     case SLVS_C_EQUAL_LENGTH_LINES:   return CONSTRAINT_EQUAL_LINES;