]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Implement Collinear constraint
authorazv <azv@opencascade.com>
Thu, 9 Mar 2017 12:24:00 +0000 (15:24 +0300)
committerazv <azv@opencascade.com>
Thu, 9 Mar 2017 12:24:19 +0000 (15:24 +0300)
src/PythonAPI/model/sketcher/tools.py
src/SketchPlugin/CMakeLists.txt
src/SketchPlugin/Test/TestConstraintCollinear.py
src/SketchPlugin/plugin-Sketch.xml
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_UpdateCoincidence.cpp
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_UpdateCoincidence.h
src/SketchSolver/SketchSolver_ConstraintCoincidence.h
src/SketchSolver/SketchSolver_ConstraintCollinear.cpp
src/SketchSolver/SketchSolver_ConstraintCollinear.h

index 31efc0f2837f28290a468aea7c0d2e3643b833ae..3603f20061b35215c312877b8a5b94ec66671af3 100644 (file)
@@ -1,6 +1,7 @@
 # Author: Sergey Pokhodenko
 # Copyright (C) 2014-20xx CEA/DEN, EDF R&D
 
+import ModelHighAPI
 
 def addPolyline(sketch, *coords):
     """Add a poly-line to sketch.
@@ -44,4 +45,7 @@ def addPolygon(sketch, *coords):
 def dof(sketch):
     """ Extract degrees of freedom for the given sketch
     """
-    return int(filter(str.isdigit, sketch.string("SolverDOF").value()))
\ No newline at end of file
+    aSketch = sketch
+    if issubclass(type(aSketch), ModelHighAPI.ModelHighAPI_Interface):
+        aSketch = sketch.feature()
+    return int(filter(str.isdigit, aSketch.string("SolverDOF").value()))
\ No newline at end of file
index 152a8fe18a9be9519b756cb0b509c407760371d1..d7fb311d34230836acd00fa9a3fec4a546b9371c 100644 (file)
@@ -121,7 +121,7 @@ INSTALL(FILES ${TEXT_RESOURCES} DESTINATION ${SHAPER_INSTALL_XML_RESOURCES})
 ADD_UNIT_TESTS(TestSketchPointLine.py
                TestSketchArcCircle.py
                TestConstraintCoincidence.py
-               TestConstraintCollinear.py
+               TestConstraintCollinear.py
                TestConstraintLength.py
                TestConstraintDistance.py
                TestConstraintParallel.py
index 8097c8e62eac83f795d54c1258959bda54307803..8e4dfdcf8b08eaa143f2d45b02ebf4104c82c53e 100644 (file)
         data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
 
 """
+
+#=========================================================================
+# Initialization of the test
+#=========================================================================
+
 from GeomDataAPI import *
 from ModelAPI import *
 import math
+import unittest
 from salome.shaper import model
 
-#=========================================================================
-# Initialization of the test
-#=========================================================================
+__updated__ = "2017-03-06"
 
-__updated__ = "2016-01-28"
+class TestConstraintCollinear(unittest.TestCase):
+  def setUp(self):
+    model.begin()
+    self.myDocument = model.moduleDocument()
+    self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+    self.myTolerance = 1.e-6
+    self.myDOF = 0
 
+  def tearDown(self):
+    model.end()
+    assert(model.checkPythonDump())
 
-def checkCollinearVec(theX1, theY1, theX2, theY2):
-    TOL = 2.e-6
+  def checkVectorCollinearity(self, theX1, theY1, theX2, theY2):
     aLen1 = math.hypot(theX1, theY1)
     aLen2 = math.hypot(theX2, theY2)
     aDot = theX1 * theX2 + theY1 * theY2
-    assert (math.fabs(math.fabs(aDot) - aLen1 * aLen2) < TOL**2)
-
-def checkCollinear(theLine1, theLine2):
-    aStartPoint1 = geomDataAPI_Point2D(theLine1.attribute("StartPoint"))
-    aEndPoint1   = geomDataAPI_Point2D(theLine1.attribute("EndPoint"))
-    aStartPoint2 = geomDataAPI_Point2D(theLine2.attribute("StartPoint"))
-    aEndPoint2   = geomDataAPI_Point2D(theLine2.attribute("EndPoint"))
-    
+    self.assertTrue(math.fabs(math.fabs(aDot) - aLen1 * aLen2) < self.myTolerance**2, "Vectors ({0}, {1}) and ({2}, {3}) do not collinear".format(theX1, theY1, theX2, theY2))
+
+  def checkLineCollinearity(self, theLine1, theLine2):
+    aStartPoint1 = theLine1.startPoint()
+    aEndPoint1   = theLine1.endPoint()
+    aStartPoint2 = theLine2.startPoint()
+    aEndPoint2   = theLine2.endPoint()
+
     aDir1x, aDir1y = aEndPoint1.x() - aStartPoint1.x(), aEndPoint1.y() - aStartPoint1.y()
     aDir2x, aDir2y = aEndPoint2.x() - aStartPoint1.x(), aEndPoint2.y() - aStartPoint1.y()
     aDir3x, aDir3y = aStartPoint2.x() - aStartPoint1.x(), aStartPoint2.y() - aStartPoint1.y()
-    checkCollinearVec(aDir1x, aDir1y, aDir2x, aDir2y)
-    checkCollinearVec(aDir1x, aDir1y, aDir3x, aDir3y)
+    self.checkVectorCollinearity(aDir1x, aDir1y, aDir2x, aDir2y)
+    self.checkVectorCollinearity(aDir1x, aDir1y, aDir3x, aDir3y)
 
+  def moveLineAndCheckCollinearity(self, theLine1, theLine2):
+    deltaX = deltaY = 10.
 
+    theLine1.startPoint().setValue(theLine1.startPoint().x() + deltaX, theLine1.startPoint().y() + deltaY)
+    model.do()
+    self.checkLineCollinearity(theLine1, theLine2)
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
 
-aSession = ModelAPI_Session.get()
-aDocument = aSession.moduleDocument()
-#=========================================================================
-# Creation of a sketch
-#=========================================================================
-aSession.startOperation()
-aSketchCommonFeature = aDocument.addFeature("Sketch")
-aSketchFeature = featureToCompositeFeature(aSketchCommonFeature)
-origin = geomDataAPI_Point(aSketchFeature.attribute("Origin"))
-origin.setValue(0, 0, 0)
-dirx = geomDataAPI_Dir(aSketchFeature.attribute("DirX"))
-dirx.setValue(1, 0, 0)
-norm = geomDataAPI_Dir(aSketchFeature.attribute("Norm"))
-norm.setValue(0, 0, 1)
-aSession.finishOperation()
-#=========================================================================
-# Create two lines
-#=========================================================================
-aSession.startOperation()
-# line A
-aSketchLineA = aSketchFeature.addFeature("SketchLine")
-aLineAStartPoint = geomDataAPI_Point2D(aSketchLineA.attribute("StartPoint"))
-aLineAEndPoint = geomDataAPI_Point2D(aSketchLineA.attribute("EndPoint"))
-aSketchLineB = aSketchFeature.addFeature("SketchLine")
-aLineAStartPoint.setValue(0., 25)
-aLineAEndPoint.setValue(85., 25)
-# line B
-aLineBStartPoint = geomDataAPI_Point2D(aSketchLineB.attribute("StartPoint"))
-aLineBEndPoint = geomDataAPI_Point2D(aSketchLineB.attribute("EndPoint"))
-aLineBStartPoint.setValue(0., 50)
-aLineBEndPoint.setValue(80., 75)
-aSession.finishOperation()
-assert (model.dof(aSketchFeature) == 8)
-#=========================================================================
-# Link lines with collinear constraint
-#=========================================================================
-aSession.startOperation()
-aParallelConstraint = aSketchFeature.addFeature("SketchConstraintCollinear")
-refattrA = aParallelConstraint.refattr("ConstraintEntityA")
-refattrB = aParallelConstraint.refattr("ConstraintEntityB")
-refattrA.setObject(aSketchLineA.firstResult())
-refattrB.setObject(aSketchLineB.firstResult())
-aParallelConstraint.execute()
-aSession.finishOperation()
-checkCollinear(aSketchLineA, aSketchLineB)
-assert (model.dof(aSketchFeature) == 6)
-#=========================================================================
-# Check values and move one constrainted object
-#=========================================================================
-deltaX = deltaY = 10.
-# rotate line, check that reference's line points are moved also
-aLineBStartPointPrev = (aLineBStartPoint.x(), aLineBStartPoint.y())
-aLineBEndPointPrev = (aLineBEndPoint.x(), aLineBEndPoint.y())
-aSession.startOperation()
-aLineAStartPoint.setValue(aLineAStartPoint.x() + deltaX,
-                          aLineAStartPoint.y() + deltaY)
-aLineAEndPoint.setValue(aLineAEndPoint.x() - deltaX,
-                        aLineAEndPoint.y() - deltaY)
-aSession.finishOperation()
-checkCollinear(aSketchLineA, aSketchLineB)
-assert (model.dof(aSketchFeature) == 6)
+    theLine1.endPoint().setValue(theLine1.endPoint().x() - deltaX, theLine1.endPoint().y() - deltaY)
+    model.do()
+    self.checkLineCollinearity(theLine1, theLine2)
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+  def test_collinear_base(self):
+    """ Test 1. Collinearity two independent lines
+    """
+    aSketchLineA = self.mySketch.addLine(0., 25., 85., 25.)
+    aSketchLineB = self.mySketch.addLine(0., 50., 80., 75.)
+    self.myDOF += 8
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+    self.mySketch.setCollinear(aSketchLineA, aSketchLineB)
+    self.myDOF -= 2
+    model.do()
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+    self.checkLineCollinearity(aSketchLineA, aSketchLineB)
+    self.moveLineAndCheckCollinearity(aSketchLineA, aSketchLineB)
+
+  def test_collinear_connected_lines(self):
+    """ Test 2. Collinearity of two lines in polyline
+    """
+    aSketchLineA = self.mySketch.addLine(10., 20., 30., 40.)
+    aSketchLineB = self.mySketch.addLine(30., 40., 30., 70.)
+    self.myDOF += 8
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+    self.mySketch.setCoincident(aSketchLineA.endPoint(), aSketchLineB.startPoint())
+    self.myDOF -= 2
+    model.do()
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+    self.mySketch.setCollinear(aSketchLineA, aSketchLineB)
+    self.myDOF -= 1
+    model.do()
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+    self.checkLineCollinearity(aSketchLineA, aSketchLineB)
+    self.moveLineAndCheckCollinearity(aSketchLineA, aSketchLineB)
+
+  def test_collinear_point_on_line(self):
+    """ Test 3. Collinearity for line which extremity is coincident with other line
+    """
+    aSketchLineA = self.mySketch.addLine(10., 20., 30., 40.)
+    aSketchLineB = self.mySketch.addLine(20., 40., 30., 70.)
+    self.myDOF += 8
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+    self.mySketch.setCoincident(aSketchLineA.result(), aSketchLineB.startPoint())
+    self.myDOF -= 1
+    model.do()
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+    self.mySketch.setCollinear(aSketchLineA, aSketchLineB)
+    self.myDOF -= 1
+    model.do()
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+    self.checkLineCollinearity(aSketchLineA, aSketchLineB)
+    self.moveLineAndCheckCollinearity(aSketchLineA, aSketchLineB)
+
+  def test_already_collinear(self):
+    """ Test 4. Collinearity two lines connected by extremities to each other
+    """
+    aSketchLineA = self.mySketch.addLine(10., 20., 40., 50.)
+    aSketchLineB = self.mySketch.addLine(20., 40., 40., 70.)
+    self.myDOF += 8
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+    self.mySketch.setCoincident(aSketchLineA.result(), aSketchLineB.startPoint())
+    self.mySketch.setCoincident(aSketchLineA.endPoint(), aSketchLineB.result())
+    self.myDOF -= 2
+    model.do()
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+    aCollinear = self.mySketch.setCollinear(aSketchLineA, aSketchLineB)
+    model.do()
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+    # check error message and remove non valid constraint
+    self.assertNotEqual(self.mySketch.solverError().value(), "")
+    self.myDocument.removeFeature(aCollinear.feature())
+    model.do()
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+  def test_already_collinear2(self):
+    """ Test 5. Collinearity of two lines when one line is fully on other
+    """
+    aSketchLineA = self.mySketch.addLine(10., 20., 30., 40.)
+    aSketchLineB = self.mySketch.addLine(20., 40., 30., 70.)
+    self.myDOF += 8
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+    self.mySketch.setCoincident(aSketchLineA.result(), aSketchLineB.startPoint())
+    self.mySketch.setCoincident(aSketchLineA.result(), aSketchLineB.endPoint())
+    self.myDOF -= 2
+    model.do()
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+    aCollinear = self.mySketch.setCollinear(aSketchLineA, aSketchLineB)
+    model.do()
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+    # check error message and remove non valid constraint
+    self.assertNotEqual(self.mySketch.solverError().value(), "")
+    self.myDocument.removeFeature(aCollinear.feature())
+    model.do()
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+if __name__ == '__main__':
+  unittest.main()
 #=========================================================================
 # End of test
 #=========================================================================
-
-assert(model.checkPythonDump())
index 5a62d12004e57761783b531b778d9240e2852e35..b72f3d8d3efaf9d2c14e3e5372b974f769622d81 100644 (file)
       </feature>
       
     <!--  SketchConstraintCollinear  -->
-      <!--
       <feature id="SketchConstraintCollinear" title="Collinear" tooltip="Create constraint defining collinearity of two lines" icon="icons/Sketch/collinear.png">
         <sketch_shape_selector id="ConstraintEntityA" 
             label="First line" tooltip="Select a line" shape_types="edge">
         </sketch_shape_selector>
         <validator id="PartSet_CollinearSelection"/>
       </feature>
-      -->
          
     </group>
     
index fcac0cb47cafd3fc2f018710517c1137ff75d3b7..9dc93f371b9b82b4fe475e763b1eb9261f618c74 100644 (file)
@@ -88,10 +88,6 @@ static ConstraintWrapperPtr
   createConstraintTangent(const SketchSolver_ConstraintType& theType,
                           std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity1,
                           std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity2);
-static ConstraintWrapperPtr
-  createConstraintCollinear(ConstraintPtr theConstraint,
-                           std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity1,
-                           std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity2);
 static ConstraintWrapperPtr
   createConstraintMiddlePoint(std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint,
                               std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity);
@@ -210,10 +206,6 @@ ConstraintWrapperPtr PlaneGCSSolver_Tools::createConstraint(
                                       GCS_ENTITY_WRAPPER(theEntity1),
                                       GCS_ENTITY_WRAPPER(theEntity2));
     break;
-  case CONSTRAINT_COLLINEAR:
-    aResult = createConstraintCollinear(theConstraint,
-                  GCS_ENTITY_WRAPPER(theEntity1), GCS_ENTITY_WRAPPER(theEntity2));
-    break;
   case CONSTRAINT_MULTI_TRANSLATION:
   case CONSTRAINT_MULTI_ROTATION:
   case CONSTRAINT_SYMMETRIC:
@@ -411,23 +403,6 @@ ConstraintWrapperPtr createConstraintHorizVert(
   return ConstraintWrapperPtr(new PlaneGCSSolver_ConstraintWrapper(aNewConstr, theType));
 }
 
-ConstraintWrapperPtr createConstraintCollinear(
-    ConstraintPtr theConstraint,
-    std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity1,
-    std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity2)
-{
-  std::shared_ptr<GCS::Line> aLine1 = std::dynamic_pointer_cast<GCS::Line>(theEntity1->entity());
-  std::shared_ptr<GCS::Line> aLine2 = std::dynamic_pointer_cast<GCS::Line>(theEntity2->entity());
-
-  // create two point-on-line constraints
-  std::list<GCSConstraintPtr> aConstrList;
-  aConstrList.push_back( GCSConstraintPtr(new GCS::ConstraintPointOnLine(aLine2->p1, *aLine1)) );
-  aConstrList.push_back( GCSConstraintPtr(new GCS::ConstraintPointOnLine(aLine2->p2, *aLine1)) );
-
-  return ConstraintWrapperPtr(
-      new PlaneGCSSolver_ConstraintWrapper(aConstrList, CONSTRAINT_COLLINEAR));
-}
-
 ConstraintWrapperPtr createConstraintParallel(
     std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity1,
     std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity2)
index ccd7d067504df7dda9f38e10fa8193c9f5198d9b..6e66ae26e36aecda630584ac3a0bea60b5db40e1 100644 (file)
@@ -5,9 +5,12 @@
 // Author:  Artem ZHIDKOV
 
 #include <PlaneGCSSolver_UpdateCoincidence.h>
+#include <PlaneGCSSolver_EntityWrapper.h>
+#include <PlaneGCSSolver_PointWrapper.h>
 #include <SketchSolver_Constraint.h>
 
 #include <SketchPlugin_ConstraintCoincidence.h>
+#include <SketchPlugin_ConstraintCollinear.h>
 #include <SketchPlugin_ConstraintMiddle.h>
 
 void PlaneGCSSolver_UpdateCoincidence::attach(SketchSolver_Constraint* theObserver,
@@ -29,7 +32,8 @@ void PlaneGCSSolver_UpdateCoincidence::attach(SketchSolver_Constraint* theObserv
 void PlaneGCSSolver_UpdateCoincidence::update(const FeaturePtr& theFeature)
 {
   if (theFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID() ||
-      theFeature->getKind() == SketchPlugin_ConstraintMiddle::ID()) {
+      theFeature->getKind() == SketchPlugin_ConstraintMiddle::ID() ||
+      theFeature->getKind() == SketchPlugin_ConstraintCollinear::ID()) {
     myCoincident.clear();
     // notify listeners and stop procesing
     std::list<SketchSolver_Constraint*>::iterator anIt = myObservers.begin();
@@ -87,6 +91,30 @@ bool PlaneGCSSolver_UpdateCoincidence::checkCoincidence(
   return isAccepted;
 }
 
+bool PlaneGCSSolver_UpdateCoincidence::isPointOnEntity(
+    const EntityWrapperPtr& thePoint,
+    const EntityWrapperPtr& theEntity)
+{
+  std::list<CoincidentEntities>::iterator anIt = myCoincident.begin();
+  for (; anIt != myCoincident.end(); ++anIt)
+    if (anIt->isExist(thePoint))
+      break;
+
+  if (anIt == myCoincident.end())
+    return false;
+
+  if (anIt->isExist(theEntity))
+    return true;
+
+  if (theEntity->type() == ENTITY_LINE) {
+    std::shared_ptr<GCS::Line> aLine = std::dynamic_pointer_cast<GCS::Line>(
+        std::dynamic_pointer_cast<PlaneGCSSolver_EntityWrapper>(theEntity)->entity());
+    return anIt->isExist(aLine->p1) || anIt->isExist(aLine->p2);
+  }
+  return false;
+}
+
+
 
 
 
@@ -127,6 +155,36 @@ bool PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::isExist(
   return false;
 }
 
+static bool isEqual(const GCS::Point& thePoint1, const GCS::Point& thePoint2)
+{
+  return thePoint1.x == thePoint2.x && thePoint1.y == thePoint2.y;
+}
+
+bool PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::isExist(
+    const GCS::Point& thePoint) const
+{
+  std::map<EntityWrapperPtr, std::set<EntityWrapperPtr> >::const_iterator
+      anIt = myExternalAndConnected.begin();
+  for (; anIt != myExternalAndConnected.end(); ++anIt) {
+    if (anIt->first && anIt->first->type() == ENTITY_POINT) {
+      const GCSPointPtr& aPoint =
+          std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(anIt->first)->point();
+      if (isEqual(*aPoint, thePoint))
+        return true;
+    }
+
+    std::set<EntityWrapperPtr>::const_iterator anEntIt = anIt->second.begin();
+    for (; anEntIt != anIt->second.end(); ++anEntIt)
+      if ((*anEntIt)->type() == ENTITY_POINT) {
+        const GCSPointPtr& aPoint =
+            std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(*anEntIt)->point();
+        if (isEqual(*aPoint, thePoint))
+          return true;
+      }
+  }
+  return false;
+}
+
 bool PlaneGCSSolver_UpdateCoincidence::CoincidentEntities::isNewCoincidence(
     const EntityWrapperPtr& theEntityExist,
     const EntityWrapperPtr& theOtherEntity)
index afd49a2a1201ca561d2713cd5b5fad9d93eb41a0..9d3b0eb99b1d2a26afe9bd530fcf1165ae7eb38f 100644 (file)
@@ -10,6 +10,8 @@
 #include <PlaneGCSSolver_Update.h>
 #include <SketchSolver_IEntityWrapper.h>
 
+#include <GCS.h>
+
 #include <map>
 
 /** \class   PlaneGCSSolver_UpdateCoincidence
@@ -45,6 +47,10 @@ public:
   /// \return \c true if the entities does not coincident
   bool checkCoincidence(const EntityWrapperPtr& theEntity1, const EntityWrapperPtr& theEntity2);
 
+  /// \brief Verifies the point is coincident to the feature
+  /// \return \c true if the point is on the feature
+  bool isPointOnEntity(const EntityWrapperPtr& thePoint, const EntityWrapperPtr& theEntity);
+
 private:
   /// \brief Container for collecting and operating coincident entities
   class CoincidentEntities
@@ -55,6 +61,8 @@ private:
 
     /// Verify the entity is already in the list
     bool isExist(const EntityWrapperPtr& theEntity) const;
+    /// Verify the point is already in the list
+    bool isExist(const GCS::Point& thePoint) const;
     /// Check the coincidence is not in list yet
     bool isNewCoincidence(const EntityWrapperPtr& theEntityExist,
                           const EntityWrapperPtr& theOtherEntity);
index 9169f0021f857470ae9699fa706965ba0798ae63..59061a302973179f667a3d7ae9e6d9ac5a76d019 100644 (file)
@@ -31,7 +31,7 @@ public:
   virtual bool remove();
 
 protected:
-  /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
+  /// \brief Converts SketchPlugin constraint to a list of solver constraints
   virtual void process();
 
   /// \brief Generate list of attributes of constraint in order useful for constraints
index f99ab425fdd8c0208a9f877069c420236d4e5c13..0d35cf485945a1562d2c51f404b6d001a0a4b740 100644 (file)
 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
 
 #include <SketchSolver_ConstraintCollinear.h>
-#include <SketchSolver_Manager.h>
+#include <SketchSolver_Error.h>
+
+#include <PlaneGCSSolver_ConstraintWrapper.h>
+#include <PlaneGCSSolver_EntityWrapper.h>
+#include <PlaneGCSSolver_PointWrapper.h>
+#include <PlaneGCSSolver_UpdateCoincidence.h>
 
 #include <SketchPlugin_Line.h>
 
-SketchSolver_ConstraintCollinear::SketchSolver_ConstraintCollinear(ConstraintPtr theConstraint)
-  : SketchSolver_Constraint(theConstraint)
+static ConstraintWrapperPtr createPointsOnLine(
+    std::shared_ptr<PlaneGCSSolver_PointWrapper>  thePoint1,
+    std::shared_ptr<PlaneGCSSolver_PointWrapper>  thePoint2,
+    std::shared_ptr<PlaneGCSSolver_EntityWrapper> theLine)
+{
+  std::shared_ptr<GCS::Line> aGCSLine = std::dynamic_pointer_cast<GCS::Line>(theLine->entity());
+
+  std::list<GCSConstraintPtr> aConstrList;
+  if (thePoint1)
+    aConstrList.push_back( GCSConstraintPtr(
+        new GCS::ConstraintPointOnLine(*thePoint1->point(), *aGCSLine)) );
+  if (thePoint2)
+    aConstrList.push_back( GCSConstraintPtr(
+        new GCS::ConstraintPointOnLine(*thePoint2->point(), *aGCSLine)) );
+
+  return aConstrList.empty() ?  ConstraintWrapperPtr() : ConstraintWrapperPtr(
+      new PlaneGCSSolver_ConstraintWrapper(aConstrList, CONSTRAINT_COLLINEAR));
+}
+
+
+void SketchSolver_ConstraintCollinear::process()
 {
+  cleanErrorMsg();
+  if (!myBaseConstraint || !myStorage) {
+    // Not enough parameters are assigned
+    return;
+  }
+
+  EntityWrapperPtr aValue;
+  std::vector<EntityWrapperPtr> anAttributes;
+  getAttributes(aValue, anAttributes);
+  if (!myErrorMsg.empty())
+    return;
+  if (anAttributes.empty()) {
+    myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
+    return;
+  }
+
+  for (int i = 0; i < 2; ++i) {
+    AttributeRefAttrPtr aRefAttr = myBaseConstraint->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
+    FeaturePtr aLine = ModelAPI_Feature::feature(aRefAttr->object());
+    myPoints[2*i] = myStorage->entity(aLine->attribute(SketchPlugin_Line::START_ID()));
+    myPoints[2*i + 1] = myStorage->entity(aLine->attribute(SketchPlugin_Line::END_ID()));
+  }
+
+  myStorage->subscribeUpdates(this, PlaneGCSSolver_UpdateCoincidence::GROUP());
+  myStorage->notify(myBaseConstraint);
 }
 
-////void SketchSolver_ConstraintCollinear::notifyCoincidenceChanged(
-////    EntityWrapperPtr theCoincAttr1,
-////    EntityWrapperPtr theCoincAttr2)
-////{
-////  bool used = true;
-////
-////  // obtain IDs of all boundary points of lines
-////  EntityID aPointIDs[4];
-////  for (int i = 0; i < 2; ++i) {
-////    AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-////        myBaseConstraint->attribute(SketchPlugin_Constraint::ATTRIBUTE(i)));
-////    if (!aRefAttr->object())
-////      continue;
-////    FeaturePtr aLine = ModelAPI_Feature::feature(aRefAttr->object());
-////    AttributePtr aLinePt = aLine->attribute(SketchPlugin_Line::START_ID());
-////    aPointIDs[2*i] = myStorage->entity(aLinePt)->id();
-////    aLinePt = aLine->attribute(SketchPlugin_Line::END_ID());
-////    aPointIDs[2*i + 1] = myStorage->entity(aLinePt)->id();
-////  }
-////
-////  EntityWrapperPtr anAttrs[2] = {theCoincAttr1, theCoincAttr2};
-////  for (int i = 0; i < 2 && used; ++i) {
-////    if (anAttrs[i]->baseAttribute())
-////      used = used && isUsed(anAttrs[i]->baseAttribute());
-////    else
-////      used = used && isUsed(anAttrs[i]->baseFeature());
-////
-////    if (!used) {
-////      if (anAttrs[i]->type() == ENTITY_POINT) {
-////        EntityID anID = anAttrs[i]->id();
-////        for (int j = 0; j < 4; ++j)
-////          if (anID == aPointIDs[j]) {
-////            used = true;
-////            break;
-////          }
-////      }
-////    }
-////  }
-////
-////  if (used) {
-////    remove();
-////    process();
-////  }
-////}
+void SketchSolver_ConstraintCollinear::notify(const FeaturePtr&      theFeature,
+                                              PlaneGCSSolver_Update* theUpdater)
+{
+  PlaneGCSSolver_UpdateCoincidence* anUpdater =
+      static_cast<PlaneGCSSolver_UpdateCoincidence*>(theUpdater);
+
+  bool isPointOnOppositeLine[4];
+  std::list<EntityWrapperPtr>::reverse_iterator anIt = myAttributes.rbegin();
+  for (int i = 0; i < 2; ++i, ++anIt) {
+    isPointOnOppositeLine[2*i] = anUpdater->isPointOnEntity(myPoints[2*i], *anIt);
+    isPointOnOppositeLine[2*i + 1] = anUpdater->isPointOnEntity(myPoints[2*i + 1], *anIt);
+  }
+
+  // both points of one line is on another line => lines are already collinear,
+  // would like to show "conflicting constraints"
+  if (isPointOnOppositeLine[0] && isPointOnOppositeLine[1])
+    isPointOnOppositeLine[1] = false;
+  if (isPointOnOppositeLine[2] && isPointOnOppositeLine[3])
+    isPointOnOppositeLine[3] = false;
+
+  bool aConstraintToApply[4] = {false, false, false, false};
+  ConstraintWrapperPtr aNewConstraint;
+  std::shared_ptr<PlaneGCSSolver_PointWrapper> aPoints[2];
+  std::shared_ptr<PlaneGCSSolver_EntityWrapper> aLine;
+
+  if (isPointOnOppositeLine[0] || isPointOnOppositeLine[1]) {
+    // one of points of first line is already on the second line,
+    // make another point of first line to be coincident with second line
+    for (int i = 0; i < 2; ++i) {
+      if (isPointOnOppositeLine[i])
+        continue;
+
+      if (!myIsConstraintApplied[i])
+        aPoints[i] = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(myPoints[i]);
+      aConstraintToApply[i] = true;
+    }
+    aLine = std::dynamic_pointer_cast<PlaneGCSSolver_EntityWrapper>(myAttributes.back());
+  } else {
+    // verify second line and add necessary constraints
+    for (int i = 0; i < 2; ++i) {
+      if (isPointOnOppositeLine[i + 2])
+        continue;
+
+      if (!myIsConstraintApplied[i+2])
+        aPoints[i] = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(myPoints[i + 2]);
+      aConstraintToApply[i+2] = true;
+    }
+    aLine = std::dynamic_pointer_cast<PlaneGCSSolver_EntityWrapper>(myAttributes.front());
+  }
+
+  bool isNew = false;
+  for (int i = 0; i < 4 && !isNew; ++i)
+    if (aConstraintToApply[i] != myIsConstraintApplied[i])
+      isNew = true;
+  if (isNew) {
+    mySolverConstraint = createPointsOnLine(aPoints[0], aPoints[1], aLine);
+    myStorage->removeConstraint(myBaseConstraint);
+    myStorage->addConstraint(myBaseConstraint, mySolverConstraint);
+  }
+}
index 7ab635581472b64ca4dc746795bd168ff00f8696..a70cc80acfc821a62d36ddf21323411a63f0dc33 100644 (file)
@@ -17,13 +17,24 @@ class SketchSolver_ConstraintCollinear : public SketchSolver_Constraint
 {
 public:
   /// Constructor based on SketchPlugin constraint
-  SketchSolver_ConstraintCollinear(ConstraintPtr theConstraint);
+  SketchSolver_ConstraintCollinear(ConstraintPtr theConstraint)
+    : SketchSolver_Constraint(theConstraint)
+  {
+    for (int i = 0; i < 4; ++i)
+      myIsConstraintApplied[i] = false;
+  }
 
-  virtual ~SketchSolver_ConstraintCollinear() {}
+  /// \brief Notify this object about the feature is changed somewhere
+  virtual void notify(const FeaturePtr&      theFeature,
+                      PlaneGCSSolver_Update* theUpdater);
 
-////  /// \brief Notify constraint, that coincidence appears or removed
-////  virtual void notifyCoincidenceChanged(EntityWrapperPtr theCoincAttr1,
-////                                        EntityWrapperPtr theCoincAttr2);
+protected:
+  /// \brief Converts SketchPlugin constraint to a list of solver constraints
+  virtual void process();
+
+private:
+  EntityWrapperPtr myPoints[4];  ///< extremities on collinear lines
+  bool myIsConstraintApplied[4]; ///< set \c true if point on opposite line
 };
 
 #endif