]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Merge remote-tracking branch 'remotes/origin/master'
authorazv <azv@opencascade.com>
Wed, 14 May 2014 07:59:51 +0000 (11:59 +0400)
committerazv <azv@opencascade.com>
Wed, 14 May 2014 07:59:51 +0000 (11:59 +0400)
src/SketchPlugin/SketchPlugin_Constraint.h
src/SketchSolver/CMakeLists.txt
src/SketchSolver/SketchSolver_ConstraintManager.cpp
src/SketchSolver/SketchSolver_ConstraintManager.h

index e69a316cc46a6b0fa4867fe09ccceda9a0553901..61cd2bf0554bc18567dbc87e17c4d48e078be365 100644 (file)
@@ -34,7 +34,8 @@ const std::string CONSTRAINT_ATTR_ENTITY_C("ConstraintEntityC");
 /// Fourth entity for the constraint
 const std::string CONSTRAINT_ATTR_ENTITY_D("ConstraintEntityD");
 /// List of constraint attributes
-const std::string CONSTRAINT_ATTRIBUTES[4] = 
+const unsigned int CONSTRAINT_ATTR_SIZE = 4;
+const std::string CONSTRAINT_ATTRIBUTES[CONSTRAINT_ATTR_SIZE] = 
                       {CONSTRAINT_ATTR_ENTITY_A, CONSTRAINT_ATTR_ENTITY_B, 
                        CONSTRAINT_ATTR_ENTITY_C, CONSTRAINT_ATTR_ENTITY_D};
 
index 5d04a4a95d0d3161dc114cd23f86e9ba09218835..70b9fecbbc4b97fcc43737dfc9d4febd20c76781 100644 (file)
@@ -15,12 +15,16 @@ SET(PROJECT_SOURCES
 SET(PROJECT_LIBRARIES
     ${SLVS_LIBRARIES}
     SketchPlugin
+    Events
 )
 
 INCLUDE_DIRECTORIES(
-    ../SketchPlugin
-    ../ModelAPI
-    ../GeomAPI
+    ${PROJECT_SOURCE_DIR}/src/SketchPlugin
+    ${PROJECT_SOURCE_DIR}/src/ModelAPI
+    ${PROJECT_SOURCE_DIR}/src/Model
+    ${PROJECT_SOURCE_DIR}/src/GeomAPI
+    ${PROJECT_SOURCE_DIR}/src/GeomDataAPI
+    ${PROJECT_SOURCE_DIR}/src/Events
 )
 
 ADD_DEFINITIONS(-DSKETCHSOLVER_EXPORTS ${BOOST_DEFINITIONS})
index 7984b031cf8d44cc6c06117439860cf8c72b11ea..777519914ed712d9bb0bcc396fac73a43f459458 100644 (file)
@@ -4,12 +4,23 @@
 
 #include "SketchSolver_ConstraintManager.h"
 
+#include <Events_Loop.h>
+#include <GeomDataAPI_Dir.h>
+#include <GeomDataAPI_Point.h>
+#include <GeomDataAPI_Point2D.h>
 #include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeRefList.h>
 #include <ModelAPI_Data.h>
+#include <Model_Events.h>
 #include <SketchPlugin_Constraint.h>
 #include <SketchPlugin_ConstraintCoincidence.h>
 #include <SketchPlugin_Line.h>
+#include <SketchPlugin_Sketch.h>
 
+SketchSolver_ConstraintManager* SketchSolver_ConstraintManager::_self = 0;
+
+/// Global constaint manager object
+SketchSolver_ConstraintManager* myManager = SketchSolver_ConstraintManager::Instance();
 
 /// This value is used to give unique index to the groups
 static Slvs_hGroup myGroupIndexer = 0;
@@ -17,9 +28,21 @@ static Slvs_hGroup myGroupIndexer = 0;
 // ========================================================
 // ========= SketchSolver_ConstraintManager ===============
 // ========================================================
+SketchSolver_ConstraintManager* SketchSolver_ConstraintManager::Instance()
+{
+  if (!_self)
+    _self = new SketchSolver_ConstraintManager();
+  return _self;
+}
+
 SketchSolver_ConstraintManager::SketchSolver_ConstraintManager()
 {
   myGroups.clear();
+
+  // Register in event loop
+  Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_CREATED));
+  Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_UPDATED));
+  Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_DELETED));
 }
 
 SketchSolver_ConstraintManager::~SketchSolver_ConstraintManager()
@@ -27,6 +50,109 @@ SketchSolver_ConstraintManager::~SketchSolver_ConstraintManager()
   myGroups.clear();
 }
 
+void SketchSolver_ConstraintManager::processEvent(const Events_Message* theMessage)
+{
+  if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_CREATED))
+  {
+    const Model_FeatureUpdatedMessage* aCreateMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
+
+    // Only sketches and constraints can be added by Create event
+    boost::shared_ptr<SketchPlugin_Sketch> aSketch = 
+      boost::dynamic_pointer_cast<SketchPlugin_Sketch>(aCreateMsg->feature());
+    if (aSketch)
+    {
+      addWorkplane(aSketch);
+      return ;
+    }
+    boost::shared_ptr<SketchPlugin_Constraint> aConstraint = 
+      boost::dynamic_pointer_cast<SketchPlugin_Constraint>(aCreateMsg->feature());
+    if (aConstraint)
+    {
+      addConstraint(aConstraint);
+      return ;
+    }
+  }
+  else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_DELETED))
+  {
+    const Model_FeatureDeletedMessage* aDeleteMsg = dynamic_cast<const Model_FeatureDeletedMessage*>(theMessage);
+    /// \todo Implement deleting objects on event
+  }
+  else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_UPDATED))
+  {
+    const Model_FeatureUpdatedMessage* aUpdateMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
+
+    boost::shared_ptr<SketchPlugin_Sketch> aSketch = 
+      boost::dynamic_pointer_cast<SketchPlugin_Sketch>(aUpdateMsg->feature());
+    if (aSketch)
+    {
+//      updateWorkplane(aSketch);
+      return ;
+    }
+
+    boost::shared_ptr<SketchPlugin_Constraint> aConstraint = 
+      boost::dynamic_pointer_cast<SketchPlugin_Constraint>(aUpdateMsg->feature());
+    if (aConstraint)
+    {
+//      updateConstraint(aConstraint);
+      return ;
+    }
+
+    boost::shared_ptr<SketchPlugin_Feature> aFeature = 
+      boost::dynamic_pointer_cast<SketchPlugin_Feature>(aUpdateMsg->feature());
+//    if (aFeature)
+//      updateEntity(aFeature);
+  }
+}
+
+
+bool SketchSolver_ConstraintManager::addWorkplane(boost::shared_ptr<SketchPlugin_Sketch> theSketch)
+{
+  // Check the specified workplane is already used
+  std::vector<SketchSolver_ConstraintGroup>::const_iterator aGroupIter;
+  for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
+    if (aGroupIter->isBaseWorkplane(theSketch))
+      return true;
+  // Create new group for workplane
+  SketchSolver_ConstraintGroup aNewGroup(theSketch);
+  // Verify that the group is created successfully
+  if (!aNewGroup.isBaseWorkplane(theSketch))
+    return false;
+  myGroups.push_back(aNewGroup);
+  return true;
+}
+
+bool SketchSolver_ConstraintManager::addConstraint(
+              boost::shared_ptr<SketchPlugin_Constraint> theConstraint)
+{
+  // Search the groups which this constraint touchs
+  std::vector<Slvs_hGroup> aGroups;
+  findGroups(theConstraint, aGroups);
+
+  // Process the groups list
+  if (aGroups.size() == 0)
+  { // There are no groups applicable for this constraint => create new one
+    SketchSolver_ConstraintGroup aGroup(findWorkplaneForConstraint(theConstraint));
+    aGroup.addConstraint(theConstraint);
+    myGroups.push_back(aGroup);
+  }
+  else if (aGroups.size() == 1)
+  { // Only one group => add constraint into it
+    Slvs_hGroup aGroupId = *(aGroups.begin());
+    std::vector<SketchSolver_ConstraintGroup>::iterator aGroupIter;
+    for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
+      if (aGroupIter->getId() == aGroupId)
+        return aGroupIter->addConstraint(theConstraint);
+  }
+  else if (aGroups.size() > 1)
+  { // Several groups applicable for this constraint => need to merge them
+    /// \todo Implement merging of groups
+  }
+
+  // Something goes wrong
+  return false;
+}
+
+
 void SketchSolver_ConstraintManager::findGroups(
               boost::shared_ptr<SketchPlugin_Constraint> theConstraint, 
               std::vector<Slvs_hGroup>&                  theGroupIDs) const
@@ -37,12 +163,33 @@ void SketchSolver_ConstraintManager::findGroups(
       theGroupIDs.push_back(aGroupIter->getId());
 }
 
+boost::shared_ptr<SketchPlugin_Sketch> SketchSolver_ConstraintManager::findWorkplaneForConstraint(
+              boost::shared_ptr<SketchPlugin_Constraint> theConstraint) const
+{
+  std::vector<SketchSolver_ConstraintGroup>::const_iterator aGroupIter;
+  for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
+  {
+    boost::shared_ptr<SketchPlugin_Sketch> aWP = aGroupIter->getWorkplane();
+    boost::shared_ptr<ModelAPI_AttributeRefList> aWPFeatures = 
+      boost::dynamic_pointer_cast<ModelAPI_AttributeRefList>(aWP->data()->attribute(SKETCH_ATTR_FEATURES));
+    std::list< boost::shared_ptr<ModelAPI_Feature> > aFeaturesList = aWPFeatures->list();
+    std::list< boost::shared_ptr<ModelAPI_Feature> >::const_iterator anIter;
+    for (anIter = aFeaturesList.begin(); anIter != aFeaturesList.end(); anIter++)
+      if (*anIter == theConstraint)
+        return aWP; // workplane is found
+  }
+
+  return boost::shared_ptr<SketchPlugin_Sketch>();
+}
+
+
 
 // ========================================================
 // =========  SketchSolver_ConstraintGroup  ===============
 // ========================================================
 
-SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::SketchSolver_ConstraintGroup()
+SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::
+  SketchSolver_ConstraintGroup(boost::shared_ptr<SketchPlugin_Sketch> theWorkplane)
   : myID(++myGroupIndexer),
     myParamMaxID(0),
     myEntityMaxID(0),
@@ -53,14 +200,15 @@ SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::SketchSolver_Const
   myEntities.clear();
   myConstraints.clear();
 
-  // The workplane will be initialized on first constraint, so its handle is NULL meanwhile
-  myWorkplane.h = 0;
-
   // Nullify all elements of the set of equations
   myConstrSet.param = 0;
   myConstrSet.entity = 0;
   myConstrSet.constraint = 0;
   myConstrSet.failed = 0;
+
+  // Initialize workplane
+  myWorkplane.h = 0;
+  addWorkplane(theWorkplane);
 }
 
 SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::~SketchSolver_ConstraintGroup()
@@ -80,6 +228,12 @@ SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::~SketchSolver_Cons
     delete [] myConstrSet.failed;
 }
 
+bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::isBaseWorkplane(
+                boost::shared_ptr<SketchPlugin_Sketch> theWorkplane) const
+{
+  return theWorkplane == mySketch;
+}
+
 bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::isInteract(
                 boost::shared_ptr<SketchPlugin_Constraint> theConstraint) const
 {
@@ -90,45 +244,36 @@ bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::isInteract(
 bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addConstraint(
                 boost::shared_ptr<SketchPlugin_Constraint> theConstraint)
 {
+  // There is no workplane yet, something wrong
   if (myWorkplane.h == 0)
-  {
-//    // Create workplane when first constraint is added
-//    std::list< boost::shared_ptr<ModelAPI_Attribute> > aWPAttr;
-//    theConstraint->getSketchParameters(aWPAttr);
-//    if (!addWorkplane(aWPAttr))
-//      return false;
-  }
+    return false;
+
+  // Get constraint type and verify the constraint parameters are correct
+  int aConstrType = getConstraintType(theConstraint);
+  if (aConstrType == SLVS_C_UNKNOWN)
+    return false;
 
   // Create constraint parameters
   double aDistance = 0.0; // scalar value of the constraint
   boost::shared_ptr<ModelAPI_AttributeDouble> aDistAttr =
     boost::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theConstraint->data()->attribute(CONSTRAINT_ATTR_VALUE));
-  if (aDistAttr.get())
+  if (aDistAttr)
     aDistance = aDistAttr->value();
 
-  /// \todo Specify the entities
-  Slvs_hEntity aPtA, aPtB, aEntityA, aEntityB; // parameters of the constraint
-  boost::shared_ptr<ModelAPI_Attribute> aEntAttr = theConstraint->data()->attribute(CONSTRAINT_ATTR_ENTITY_A);
-  aPtA = addEntity(aEntAttr);
-  if (aPtA == 0) return false;
-  aEntAttr = theConstraint->data()->attribute(CONSTRAINT_ATTR_ENTITY_B);
-  aPtB = addEntity(aEntAttr);
-  if (aPtB == 0) return false;
-  aEntAttr = theConstraint->data()->attribute(CONSTRAINT_ATTR_ENTITY_C);
-  aEntityA = addEntity(aEntAttr);
-  if (aEntityA == 0) return false;
-  aEntAttr = theConstraint->data()->attribute(CONSTRAINT_ATTR_ENTITY_D);
-  aEntityB = addEntity(aEntAttr);
-  if (aEntityB == 0) return false;
-
-  // Constraint type
-  int aConstrType = getConstraintType(theConstraint);
-  if (aConstrType == 0) return false;
+  Slvs_hEntity aConstrEnt[CONSTRAINT_ATTR_SIZE]; // parameters of the constraint
+  for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++)
+  {
+    boost::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr = 
+      boost::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+        theConstraint->data()->attribute(CONSTRAINT_ATTRIBUTES[indAttr])
+      );
+    aConstrEnt[indAttr] = addEntity(aConstrAttr->attr());
+  }
 
   // Create SolveSpace constraint structure
   Slvs_Constraint aConstraint = 
     Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType, myWorkplane.h, 
-                        aDistance, aPtA, aPtB, aEntityA, aEntityB);
+                        aDistance, aConstrEnt[0], aConstrEnt[1], aConstrEnt[2], aConstrEnt[3]);
   myConstraints.push_back(aConstraint);
   myConstraintMap[theConstraint] = *(myConstraints.rbegin());
 
@@ -138,56 +283,139 @@ bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addConstraint
 Slvs_hEntity SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addEntity(
                 boost::shared_ptr<ModelAPI_Attribute> theEntity)
 {
-  /// \todo Should be implemented
+  // Look over supported types of entities
+
+  // Point in 3D
+  boost::shared_ptr<GeomDataAPI_Point> aPoint = 
+    boost::dynamic_pointer_cast<GeomDataAPI_Point>(theEntity);
+  if (aPoint)
+  {
+    Slvs_hParam aX = addParameter(aPoint->x());
+    Slvs_hParam aY = addParameter(aPoint->y());
+    Slvs_hParam aZ = addParameter(aPoint->z());
+    Slvs_Entity aPtEntity = Slvs_MakePoint3d(++myEntityMaxID, myID, aX, aY, aZ);
+    myEntities.push_back(aPtEntity);
+    return aPtEntity.h;
+  }
+
+  // Point in 2D
+  boost::shared_ptr<GeomDataAPI_Point2D> aPoint2D = 
+    boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEntity);
+  if (aPoint2D)
+  {
+    // The 2D points are created on workplane. So, if there is no workplane yet, then error
+    if (myWorkplane.h == 0)
+      return 0;
+    Slvs_hParam aU = addParameter(aPoint2D->x());
+    Slvs_hParam aV = addParameter(aPoint2D->y());
+    Slvs_Entity aPt2DEntity = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, aU, aV);
+    myEntities.push_back(aPt2DEntity);
+    return aPt2DEntity.h;
+  }
+
+  /// \todo Other types of entities
+  
+  // Unsupported or wrong entity type
   return 0;
 }
 
+Slvs_hEntity SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addNormal(
+                boost::shared_ptr<ModelAPI_Attribute> theDirX, 
+                boost::shared_ptr<ModelAPI_Attribute> theDirY)
+{
+  boost::shared_ptr<GeomDataAPI_Dir> aDirX = boost::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirX);
+  boost::shared_ptr<GeomDataAPI_Dir> aDirY = boost::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirY);
+  if (!aDirX || !aDirY)
+    return 0;
+
+  // quaternion parameters of normal vector
+  double qw, qx, qy, qz;
+  Slvs_MakeQuaternion(aDirX->x(), aDirX->y(), aDirX->z(), 
+                      aDirY->x(), aDirY->y(), aDirY->z(), 
+                      &qw, &qx, &qy, &qz);
+
+  // Create a normal
+  Slvs_Entity aNormal = Slvs_MakeNormal3d(++myEntityMaxID, myID, 
+                      addParameter(qw), addParameter(qx), addParameter(qy), addParameter(qz));
+  myEntities.push_back(aNormal);
+  return aNormal.h;
+}
+
+
 bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addWorkplane(
-                std::list< boost::shared_ptr<ModelAPI_Attribute> >& theParams)
+                boost::shared_ptr<SketchPlugin_Sketch> theSketch)
 {
-  /// \todo Should be implemented
-  return false;
+  if (myWorkplane.h)
+    return false; // the workplane already exists
+
+  // Get parameters of workplane
+  boost::shared_ptr<ModelAPI_Attribute> aDirX    = theSketch->data()->attribute(SKETCH_ATTR_DIRX);
+  boost::shared_ptr<ModelAPI_Attribute> aDirY    = theSketch->data()->attribute(SKETCH_ATTR_DIRY);
+  boost::shared_ptr<ModelAPI_Attribute> anOrigin = theSketch->data()->attribute(SKETCH_ATTR_ORIGIN);
+  // Transform them into SolveSpace format
+  Slvs_hEntity aNormalWP = addNormal(aDirX, aDirY);
+  if (!aNormalWP) return false;
+  Slvs_hEntity anOriginWP = addEntity(anOrigin);
+  if (!anOriginWP) return false;
+  // Create workplane
+  myWorkplane = Slvs_MakeWorkplane(++myEntityMaxID, myID, anOriginWP, aNormalWP);
+  mySketch = theSketch;
+  // Workplane should be added to the list of entities
+  myEntities.push_back(myWorkplane);
+  return true;
+}
+
+Slvs_hParam SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addParameter(double theParam)
+{
+  Slvs_Param aParam = Slvs_MakeParam(++myParamMaxID, myID, theParam);
+  myParams.push_back(aParam);
+  return aParam.h;
 }
 
 int SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::getConstraintType(
                 const boost::shared_ptr<SketchPlugin_Constraint>& theConstraint) const
 {
-//  if (theConstraint->getKind() == SketchPlugin_ConstraintDistance().getKind())
-//  {
-//    boost::shared_ptr<ModelAPI_Attribute> aPtA  = theConstraint->data()->attribute(CONSTRAINT_ATTR_POINT_A);
-//    boost::shared_ptr<ModelAPI_Attribute> aPtB  = theConstraint->data()->attribute(CONSTRAINT_ATTR_POINT_B);
-//    boost::shared_ptr<ModelAPI_Attribute> aEntA = theConstraint->data()->attribute(CONSTRAINT_ATTR_ENTITY_A);
-//    boost::shared_ptr<ModelAPI_Attribute> aEntB = theConstraint->data()->attribute(CONSTRAINT_ATTR_ENTITY_B);
-//    boost::shared_ptr<ModelAPI_AttributeDouble> aDistance = 
-//      boost::shared_dynamic_cast<ModelAPI_AttributeDouble>(theConstraint->data()->attribute(CONSTRAINT_ATTR_VALUE));
-//    if (aPtA.get()) // ptA is an attribute of the constraint
-//    {
-////      if (aEntA.get()) // entityA is an attribute of the constraint
-////      {
-////        if (aEntA->feature()->getKind() == SketchPlugin_Line().getKind()) // entityA is a line
-////        {
-////          if (aEntB.get() && aEntB->feature()->getKind() == SketchPlugin_Line().getKind()) // entityB is a line too
-////            return SLVS_C_ANGLE;
-////          else if (aPtB.get()) // ptB is also an attribute of the constraint
-////            return SLVS_C_PROJ_PT_DISTANCE;
-////          else
-////            return SLVS_C_PT_LINE_DISTANCE;
-////        }
-////        /// \todo Implement other point-entity distances
-////      }
-////      else 
-//      if (aPtB.get()) // ptB is an attribute of the constrtaint => point-point distance
-//      {
-//        if (aDistance->value() == 0.0)
-//          return SLVS_C_POINTS_COINCIDENT;
-//        else 
-//          return SLVS_C_PT_PT_DISTANCE;
-//      }
-//    }
-//    else if (aEntA.get() && !aEntB.get() && !aPtB.get())
-//      return SLVS_C_DIAMETER;
-//    return SLVS_C_UNKNOWN;
-//  }
+  // Constraint for coincidence of two points
+  boost::shared_ptr<SketchPlugin_ConstraintCoincidence> aPtEquiv = 
+    boost::dynamic_pointer_cast<SketchPlugin_ConstraintCoincidence>(theConstraint);
+  if (aPtEquiv)
+  {
+    // Verify the constraint has only two attributes and they are points
+    int aPt2d = 0; // bit-mapped field, each bit indicates whether the attribute is 2D point 
+    int aPt3d = 0; // bit-mapped field, the same information for 3D points
+    for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++)
+    {
+      boost::shared_ptr<ModelAPI_AttributeRefAttr> anAttr = 
+        boost::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+          theConstraint->data()->attribute(CONSTRAINT_ATTRIBUTES[indAttr])
+        );
+      // Verify the attribute is a 2D point
+      boost::shared_ptr<GeomDataAPI_Point2D> aPoint2D = 
+        boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr->attr());
+      if (aPoint2D)
+      {
+        aPt2d |= (1 << indAttr);
+        continue;
+      }
+      // Verify the attribute is a 3D point
+      boost::shared_ptr<GeomDataAPI_Point> aPoint3D = 
+        boost::dynamic_pointer_cast<GeomDataAPI_Point>(anAttr->attr());
+      if (aPoint3D)
+      {
+        aPt3d |= (1 << indAttr);
+        continue;
+      }
+      // Attribute neither 2D nor 3D point is not supported by this type of constraint
+      return SLVS_C_UNKNOWN;
+    }
+    // The constrained points should be in first and second positions,
+    // so the expected value of aPt2d or aPt3d is 3
+    if ((aPt2d == 3 && aPt3d == 0) || (aPt2d == 0 && aPt3d == 3))
+      return SLVS_C_POINTS_COINCIDENT;
+    // Constraint parameters are wrong
+    return SLVS_C_UNKNOWN;
+  }
+
   /// \todo Implement other kind of constrtaints
 
   return SLVS_C_UNKNOWN;
index 7bd108df6f62ad480d2a563bbc976de6e99a5959..d80b9d9dc8784837583409f035978ffec2756d10 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "SketchSolver.h"
 
+#include <Events_Listener.h>
 #include <SketchPlugin_Constraint.h>
 
 // Need to be defined before including SolveSpace to avoid additional dependances on Windows platform
@@ -25,15 +26,29 @@ typedef unsigned int UINT32;
 
 /** \class   SketchSolver_ConstraintManager
  *  \ingroup DataModel
- *  \brief   Transforms the Constraint feature into the format understandable by SolveSpace library.
+ *  \brief   Listens the changes of SketchPlugin features and transforms the Constraint 
+ *           feature into the format understandable by SolveSpace library.
  *
- *  Constraints created for SolveSpace library will be divided into the groups.
+ *  Constraints created for SolveSpace library are divided into the groups.
  *  The division order based on connectedness of the features by the constraints.
  *  The groups may be fused or separated according to the new constraints.
+ *
+ *  \remark This is a singleton.
  */
-class SketchSolver_ConstraintManager
+class SketchSolver_ConstraintManager : public Events_Listener
 {
 public:
+  /** \brief Main method to create constraint manager
+   *  \return pointer to the singleton
+   */
+  static SketchSolver_ConstraintManager* Instance();
+
+  /** \brief Implementation of Event Listener method
+   *  \param[in] theMessage the data of the event
+   */
+  virtual void processEvent(const Events_Message* theMessage);
+
+protected:
   SketchSolver_ConstraintManager();
   ~SketchSolver_ConstraintManager();
 
@@ -41,13 +56,44 @@ public:
    *  \param[in] theConstraint constraint to be added
    *  \return \c true if the constraint added successfully
    */
-  SKETCHSOLVER_EXPORT bool addConstraint(boost::shared_ptr<SketchPlugin_Constraint> theConstraint);
+  bool addConstraint(boost::shared_ptr<SketchPlugin_Constraint> theConstraint);
 
   /** \brief Removes a constraint from the manager
    *  \param[in] theConstraint constraint to be removed
    *  \return \c true if the constraint removed successfully
    */
-  SKETCHSOLVER_EXPORT bool removeConstraint(boost::shared_ptr<SketchPlugin_Constraint> theConstraint);
+  bool removeConstraint(boost::shared_ptr<SketchPlugin_Constraint> theConstraint);
+
+  /** \brief Updates a constraint
+   *  \param[in] theConstraint constraint to be updated
+   *  \return \c true if the constraint was updated
+   */
+  bool updateConstraint(boost::shared_ptr<SketchPlugin_Constraint> theConstraint);
+
+  /** \brief Adds a workplane into the manager
+   *  \param[in] theSketch the feature to create workplane
+   *  \return \c true if the workplane added successfully
+   */
+  bool addWorkplane(boost::shared_ptr<SketchPlugin_Sketch> theSketch);
+
+  /** \brief Removes a workplane from the manager. 
+   *         All groups based on such workplane will be removed too.
+   *  \param[in] theSketch the feature to be removed
+   *  \return \c true if the workplane removed successfully
+   */
+  bool removeWorkplane(boost::shared_ptr<SketchPlugin_Sketch> theSketch);
+
+  /** \brief Updates a workplane
+   *  \param[in] theSketch workplane to be updated
+   *  \return \c true if the workplane was updated
+   */
+  bool updateWorkplane(boost::shared_ptr<SketchPlugin_Sketch> theSketch);
+
+  /** \brief Updates entity which is neither workplane nor constraint
+   *  \param[in] theFeature entity to be updated
+   *  \return \c true if the entity updated successfully
+   */
+  bool updateEntity(boost::shared_ptr<SketchPlugin_Feature> theFeature);
 
 private:
   class SketchSolver_ConstraintGroup;
@@ -59,8 +105,16 @@ private:
   void findGroups(boost::shared_ptr<SketchPlugin_Constraint> theConstraint, 
                   std::vector<Slvs_hGroup>&                  theGroupIDs) const;
 
+  /** \brief Searches in the list of groups the workplane which constains specified constraint
+   *  \param[in] theConstraint constraint to be found
+   *  \return workplane contains the constraint
+   */
+  boost::shared_ptr<SketchPlugin_Sketch> findWorkplaneForConstraint(
+                  boost::shared_ptr<SketchPlugin_Constraint> theConstraint) const;
+
 private:
-  std::vector<SketchSolver_ConstraintGroup> myGroups; ///< groups of constraints
+  static SketchSolver_ConstraintManager*    _self;    ///< Self pointer to implement singleton functionality
+  std::vector<SketchSolver_ConstraintGroup> myGroups; ///< Groups of constraints
 };
 
 
@@ -71,7 +125,10 @@ private:
 class SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup
 {
 public:
-  SketchSolver_ConstraintGroup();
+  /** \brief New group based on specified workplane
+   */
+  SketchSolver_ConstraintGroup(boost::shared_ptr<SketchPlugin_Sketch> theWorkplane);
+
   ~SketchSolver_ConstraintGroup();
 
   /// \brief Returns group's unique identifier
@@ -96,19 +153,41 @@ public:
    */
   bool isInteract(boost::shared_ptr<SketchPlugin_Constraint> theConstraint) const;
 
-protected:
-  /** \brief Creates a workplane from the sketch parameters
-   *  \param[in] theParams list of the basic parameters of the workplane
-   *  \return \c true if success
+  /** \brief Verifies the specified workplane is the same as a base workplane for this group
+   *  \param[in] theWorkplane workplane to be compared
+   *  \return \c true if workplanes are the same
    */
-  bool addWorkplane(std::list< boost::shared_ptr<ModelAPI_Attribute> >& theParams);
+  bool isBaseWorkplane(boost::shared_ptr<SketchPlugin_Sketch> theWorkplane) const;
 
+  boost::shared_ptr<SketchPlugin_Sketch> getWorkplane() const
+  { return mySketch; }
+
+protected:
   /** \brief Adds an entity into the group
+   *
+   *  The parameters of entity will be parsed and added to the list of SolveSpace parameters.
+   *  Parameters of certain entity will be placed sequentially in the list.
+   *
    *  \param[in] theEntity the object of constraint
    *  \return identifier of created entity or 0 if entity was not added
    */
   Slvs_hEntity addEntity(boost::shared_ptr<ModelAPI_Attribute> theEntity);
 
+  /** \brief Adds a normal into the group
+   *
+   *  Normal is a special entity in SolveSpace, which defines a direction in 3D and 
+   *  a rotation about this direction. So, SolveSpace represents normals as unit quaternions.
+   *
+   *  To define a normal there should be specified two coordinate axis 
+   *  on the plane transversed to created normal.
+   *
+   *  \param[in] theDirX first coordinate axis of the plane
+   *  \param[in] theDirY second coordinate axis of the plane
+   *  \return identifier of created normal
+   */
+  Slvs_hEntity addNormal(boost::shared_ptr<ModelAPI_Attribute> theDirX, 
+                         boost::shared_ptr<ModelAPI_Attribute> theDirY);
+
   /** \brief Adds a parameter into the group
    *  \param[in] theParam parameter to be added
    *  \return identifier of created parameter or 0 if it was not added
@@ -116,21 +195,33 @@ protected:
   Slvs_hParam addParameter(double theParam);
 
   /** \brief Compute constraint type according to SolveSpace identifiers
+   *         and verify that constraint parameters are correct
    *  \param[in] theConstraint constraint which type should be determined
-   *  \return identifier of constraint type
+   *  \return identifier of constraint type or SLVS_C_UNKNOWN if the type is wrong
    */
   int getConstraintType(const boost::shared_ptr<SketchPlugin_Constraint>& theConstraint) const;
 
 private:
+  /** \brief Creates a workplane from the sketch parameters
+   *  \param[in] theSketch parameters of workplane are the attributes of this sketch
+   *  \return \c true if success
+   */
+  bool addWorkplane(boost::shared_ptr<SketchPlugin_Sketch> theSketch);
+
+private:
+  // SolveSpace entities
   Slvs_hGroup                  myID;            ///< the index of the group
   Slvs_Entity                  myWorkplane;     ///< Workplane for the current group
   std::vector<Slvs_Param>      myParams;        ///< List of parameters of the constraints
-  Slvs_hParam                  myParamMaxID;    ///< Actual maximal ID of parameters
+  Slvs_hParam                  myParamMaxID;    ///< Actual maximal ID of parameters (not equal to myParams size)
   std::vector<Slvs_Entity>     myEntities;      ///< List of entities of the constaints
-  Slvs_hEntity                 myEntityMaxID;   ///< Actual maximal ID of entities
+  Slvs_hEntity                 myEntityMaxID;   ///< Actual maximal ID of entities (not equal to myEntities size)
   std::vector<Slvs_Constraint> myConstraints;   ///< List of constraints in SolveSpace format
-  Slvs_hConstraint             myConstrMaxID;   ///< Actual maximal ID of constraints
+  Slvs_hConstraint             myConstrMaxID;   ///< Actual maximal ID of constraints (not equal to myConstraints size)
   Slvs_System                  myConstrSet;     ///< SolveSpace's set of equations obtained by constraints
+
+  // SketchPlugin entities
+  boost::shared_ptr<SketchPlugin_Sketch> mySketch; ///< Equivalent to workplane
   std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_Constraint> 
                                myConstraintMap; ///< The map between SketchPlugin and SolveSpace constraints
 };