]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Task 2.5 Show where the remaining degrees of freedom are (issue #2997)
authorazv <azv@opencascade.com>
Mon, 14 Oct 2019 14:01:33 +0000 (17:01 +0300)
committerazv <azv@opencascade.com>
Mon, 14 Oct 2019 14:03:14 +0000 (17:03 +0300)
* Complete searching the non-constrained entities.
* Create unit test.

14 files changed:
src/Events/Events.i
src/Events/Events_Listener.h
src/GeomDataAPI/CMakeLists.txt
src/GeomDataAPI/GeomDataAPI_swig.h
src/ModelAPI/CMakeLists.txt
src/ModelAPI/ModelAPI.i
src/ModelAPI/ModelAPI_swig.h
src/PartSet/PartSet_WidgetSketchLabel.cpp
src/SketchPlugin/CMakeLists.txt
src/SketchPlugin/Test/TestRemainingDoF.py [new file with mode: 0644]
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.cpp
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.h
src/SketchSolver/SketchSolver_Manager.cpp
src/SketchSolver/SketchSolver_Manager.h

index aa09fbbee2c4db7980b22df440d9a19642c4346a..5b543e58c54c666c7905784776e3fed70eca732b 100644 (file)
 //
 
 /* Events.i */
-%module EventsAPI
+%module(directors="1") EventsAPI
+%feature("director:except") {
+    if ($error != NULL) {
+      PyErr_Print();
+      std::cerr << std::endl;
+      throw Swig::DirectorMethodException();
+    }
+}
+
 %{
   #include "Events.h"
   #include "Events_InfoMessage.h"
+  #include "Events_Listener.h"
+  #include "Events_Loop.h"
   #include "Events_Message.h"
+  #include "Events_MessageGroup.h"
 %}
 
 
 %include "typemaps.i"
 %include "std_string.i"
 
+// directors
+%feature("director") Events_Listener;
+
 // all supported interfaces
 %include "Events_Message.h"
 %include "Events_InfoMessage.h"
+%include "Events_Listener.h"
+%include "Events_Loop.h"
+%include "Events_MessageGroup.h"
index 07fd93f97996dfe14b1b57b60f33c19937574698..a7da686f67fe6d272141daf1fdb84a8ae829f985 100644 (file)
@@ -38,7 +38,9 @@ class Events_Listener {
   /// map from event ID to groupped messages (for flush for groupMessages=true listeners)
   std::map<char*, std::shared_ptr<Events_Message> > myGroups;
 
- public:
+public:
+  virtual ~Events_Listener() {}
+
   //! This method is called by loop when the event is started to process.
   EVENTS_EXPORT virtual void processEvent(const std::shared_ptr<Events_Message>& theMessage) = 0;
 
index fa7830d936d05df07be7ede37672a10b26c245c1..ecc087c26d2dfbc9722f0fbc67ecb5d0e8fd2b28 100644 (file)
@@ -41,6 +41,7 @@ SET(PROJECT_LIBRARIES
 
 INCLUDE_DIRECTORIES(
   ../GeomAPI        # only for SWIG
+  ../Events         # only for SWIG
   ../ModelAPI
 )
 
index df13808e459934ca4cd9946a2f4a2d5442492a43..b23de60169fc52bbaff275f51837ed215f67d7c8 100644 (file)
@@ -22,6 +22,7 @@
 
   #include <GeomAPI_swig.h>
   #include <ModelAPI_swig.h>
+  #include <Events_MessageGroup.h>
 
   #include "GeomDataAPI.h"
   #include "GeomDataAPI_Point.h"
index 1ef43263f40abdae8a3f11daf77b0c21f49d7d9c..a1894001e694def50b1455874b06ddf7c73ec1db 100644 (file)
@@ -118,7 +118,7 @@ SET(PROJECT_LIBRARIES
     Config
     GeomAPI
 )
-SET(CMAKE_SWIG_FLAGS -threads -w325,321,362,383,302,403,473)
+SET(CMAKE_SWIG_FLAGS -threads -w325,321,362,383,302,403,451,473)
 ADD_DEFINITIONS(-DMODELAPI_EXPORTS)
 
 ADD_LIBRARY(ModelAPI SHARED ${PROJECT_SOURCES} ${PROJECT_HEADERS})
index dc76645c858400c27b191d35e251c9fc336ff224..913b41b8bebc172ab07dbef5f135e83ab0ed2b4d 100644 (file)
@@ -36,6 +36,7 @@
 
 // import other modules
 %import "GeomAPI.i"
+%import "Events.i"
 
 // to avoid error on this
 #define MODELAPI_EXPORT
@@ -96,6 +97,7 @@
 %shared_ptr(ModelAPI_ResultField)
 %shared_ptr(ModelAPI_ResultParameter)
 %shared_ptr(ModelAPI_ResultCompSolid)
+%shared_ptr(ModelAPI_ObjectUpdatedMessage)
 
 %typecheck(SWIG_TYPECHECK_POINTER) const ModelAPI_AttributeTables::Value {
   $1 = (PyFloat_Check($input) || PyLong_Check($input) || PyUnicode_Check($input) || PyBool_Check($input)) ? 1 : 0;
 
 // all supported interfaces
 %include "ModelAPI_Entity.h"
+%include "ModelAPI_Events.h"
 %include "ModelAPI_Document.h"
 %include "ModelAPI_Session.h"
 %include "ModelAPI_Plugin.h"
 // std::set -> []
 %template(AttributeSet) std::set<std::shared_ptr<ModelAPI_Attribute> >;
 %template(FeatureSet) std::set<std::shared_ptr<ModelAPI_Feature> >;
+%template(ObjectSet) std::set<std::shared_ptr<ModelAPI_Object> >;
 
 // std::dynamic_pointer_cast
 template<class T1, class T2> std::shared_ptr<T1> shared_ptr_cast(std::shared_ptr<T2> theObject);
@@ -192,6 +196,8 @@ template<class T1, class T2> std::shared_ptr<T1> shared_ptr_cast(std::shared_ptr
 %template(modelAPI_ResultGroup) shared_ptr_cast<ModelAPI_ResultGroup, ModelAPI_Result>;
 %template(modelAPI_ResultField) shared_ptr_cast<ModelAPI_ResultField, ModelAPI_Result>;
 
+%template(messageToUpdatedMessage) shared_ptr_cast<ModelAPI_ObjectUpdatedMessage, Events_Message>;
+
 // Attribute casts
 %template(modelAPI_AttributeDocRef)        shared_ptr_cast<ModelAPI_AttributeDocRef, ModelAPI_Attribute>;
 %template(modelAPI_AttributeDouble)        shared_ptr_cast<ModelAPI_AttributeDouble, ModelAPI_Attribute>;
index 2187c2ae41cf1ca29cbb66a396da298566eec586..de4312c62408c486f42c0d6e4831818e82c0cfd0 100644 (file)
@@ -24,6 +24,7 @@
 
   #include "ModelAPI.h"
   #include "ModelAPI_Entity.h"
+  #include "ModelAPI_Events.h"
   #include "ModelAPI_Document.h"
   #include "ModelAPI_Session.h"
   #include "ModelAPI_Object.h"
index 1cdd66a5c324e3abef1ac08de2866e98e3dd6bb3..60de04c91fbef8c165500fd3fe3e0479d74fd379 100644 (file)
@@ -780,7 +780,7 @@ void PartSet_WidgetSketchLabel::onShowDOF()
   CompositeFeaturePtr aCompFeature = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(myFeature);
   if (aCompFeature.get()) {
     static const Events_ID anEvent = Events_Loop::eventByName(EVENT_GET_DOF_OBJECTS);
-    ModelAPI_EventCreator::get()->sendUpdated(aCompFeature->subFeature(0), anEvent);
+    ModelAPI_EventCreator::get()->sendUpdated(aCompFeature, anEvent);
     Events_Loop::loop()->flush(anEvent);
   }
 }
index 1edde96b787f1727fe859a269003b38860465146..1e7a20b4e2ebf584d8402dd6158eb832ddd1f0bf 100644 (file)
@@ -284,6 +284,7 @@ ADD_UNIT_TESTS(
   TestProjectionIntoResult.py
   TestProjectionUpdate.py
   TestRectangle.py
+  TestRemainingDoF.py
   TestRemoveEllipse.py
   TestRemoveEllipticArc.py
   TestRemoveSketch.py
diff --git a/src/SketchPlugin/Test/TestRemainingDoF.py b/src/SketchPlugin/Test/TestRemainingDoF.py
new file mode 100644 (file)
index 0000000..539c2df
--- /dev/null
@@ -0,0 +1,65 @@
+# Copyright (C) 2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from salome.shaper import model
+
+from EventsAPI import *
+from ModelAPI import *
+
+class FreeShapesListener(EventsAPI.Events_Listener):
+    def __init__(self):
+        Events_Listener.__init__(self)
+        # register as a listener
+        Events_Loop.loop().registerListener(self, Events_Loop.eventByName("DoFObjects"))
+        self.myEventProcessed = False
+
+    def __del__(self):
+        Events_Loop.loop().removeListener(self)
+
+    def processEvent(self, theMessage):
+        message = messageToUpdatedMessage(theMessage)
+        objs = message.objects()
+        assert(len(objs) == 1)
+        assert(objectToFeature(objs[0]).getKind() == "SketchCircle")
+        self.myEventProcessed = True
+
+
+if __name__ == "__main__":
+    # create the listener
+    listener = FreeShapesListener()
+
+    model.begin()
+    partSet = model.moduleDocument()
+    Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+    SketchCircle_1 = Sketch_1.addCircle(-30, 0, 14)
+    SketchLine_1 = Sketch_1.addLine(-30, 0, 0, 0)
+    SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchCircle_1.center(), SketchLine_1.startPoint())
+    SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "Origin"), False)
+    SketchPoint_1 = SketchProjection_1.createdFeature()
+    SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchPoint_1.result())
+    SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+    SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), 30)
+    model.end()
+
+    # send message to find the free shapes in the sketch
+    event = Events_Loop.eventByName("GetDoFObjects")
+    ModelAPI_EventCreator.get().sendUpdated(Sketch_1.feature(), event);
+    Events_Loop.loop().flush(event);
+
+    assert(listener.myEventProcessed)
index cfa6ccccb018012c4b28b9b54fc55d0610e39bbb..30b12ec7b20b962c9249f8da229c66e1dad2675a 100644 (file)
@@ -62,11 +62,11 @@ void PlaneGCSSolver_Solver::addConstraint(const ConstraintID& theMultiConstraint
     GCSConstraintPtr aConstraint = *anIt;
     aConstraint->setTag(anID);
     myEquationSystem->addConstraint(aConstraint.get());
-    myConstraints[theMultiConstraintID].insert(aConstraint);
 
     if (anID > CID_UNKNOWN)
       ++anID;
   }
+  myConstraints[theMultiConstraintID] = theConstraints;
 
   if (theMultiConstraintID >= CID_UNKNOWN)
     myDOF = -1;
@@ -77,7 +77,7 @@ void PlaneGCSSolver_Solver::removeConstraint(const ConstraintID& theID)
 {
   ConstraintMap::iterator aFound = myConstraints.find(theID);
   if (aFound != myConstraints.end()) {
-    for (std::set<GCSConstraintPtr>::iterator anIt = aFound->second.begin();
+    for (std::list<GCSConstraintPtr>::iterator anIt = aFound->second.begin();
          anIt != aFound->second.end(); ++anIt)
       myEquationSystem->clearByTag((*anIt)->getTag());
 
@@ -243,12 +243,30 @@ void PlaneGCSSolver_Solver::diagnose(const GCS::Algorithm& theAlgo)
   myDiagnoseBeforeSolve = false;
 }
 
-void PlaneGCSSolver_Solver::getFreeParameters(GCS::VEC_pD& theFreeParams) const
+void PlaneGCSSolver_Solver::getFreeParameters(GCS::VEC_pD& theFreeParams)
 {
   if (myConstraints.empty())
     theFreeParams = myParameters;
-  else
+  else {
+    GCS::VEC_pD aParametersCopy = myParameters;
+    ConstraintMap aConstraintCopy = myConstraints;
+
+    // clear the set of equations
+    clear();
+    // reset constraints
+    myParameters = aParametersCopy;
+    for (ConstraintMap::iterator anIt = aConstraintCopy.begin();
+         anIt != aConstraintCopy.end(); ++anIt)
+      addConstraint(anIt->first, anIt->second);
+
+    // parameters detection works for Dense QR only
+    GCS::QRAlgorithm aQRAlgo = myEquationSystem->qrAlgorithm;
+    myEquationSystem->qrAlgorithm = GCS::EigenDenseQR;
+    diagnose();
     myEquationSystem->getDependentParams(theFreeParams);
+    // revert QR decomposition algorithm
+    myEquationSystem->qrAlgorithm = aQRAlgo;
+  }
 }
 
 void PlaneGCSSolver_Solver::addFictiveConstraintIfNecessary()
index e6c1b4ba5940c695c2653e270c1c704770ad3070..290136b25cec55f58eaacc0864ababe7afa8dbc1 100644 (file)
@@ -80,7 +80,7 @@ public:
   void diagnose(const GCS::Algorithm& theAlgo = GCS::DogLeg);
 
   /// \brief Return the list of modifiable parameters
-  void getFreeParameters(GCS::VEC_pD& theFreeParams) const;
+  void getFreeParameters(GCS::VEC_pD& theFreeParams);
 
   /// \brief Degrees of freedom
   int dof();
@@ -94,7 +94,7 @@ private:
   void removeFictiveConstraint();
 
 private:
-  typedef std::map<ConstraintID, std::set<GCSConstraintPtr> > ConstraintMap;
+  typedef std::map<ConstraintID, std::list<GCSConstraintPtr> > ConstraintMap;
 
   GCS::VEC_pD                  myParameters;     ///< list of unknowns
   ConstraintMap                myConstraints;    ///< list of constraints
index 6f000ec6c8d91a46d443836ae7d4a8a231172ee9..a9d47533e95b12fb5cb18ad2dc632add3e8c13a5 100644 (file)
@@ -231,8 +231,8 @@ void SketchSolver_Manager::processEvent(
     if (aObjects.size() == 1) {
       std::set<ObjectPtr>::const_iterator aIt;
       for (aIt = aObjects.cbegin(); aIt != aObjects.cend(); aIt++) {
-        std::shared_ptr<SketchPlugin_Feature> aFeature =
-          std::dynamic_pointer_cast<SketchPlugin_Feature>(*aIt);
+        CompositeFeaturePtr aFeature =
+            std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(*aIt);
         if (aFeature) {
           SketchGroupPtr aGroup = findGroup(aFeature);
 
@@ -245,7 +245,7 @@ void SketchSolver_Manager::processEvent(
             aFeatures.push_back(*aIt);
           }
 
-          // TODO: send features to GUI
+          // send features to GUI
           static const Events_ID anEvent = Events_Loop::eventByName(EVENT_DOF_OBJECTS);
           ModelAPI_EventCreator::get()->sendUpdated(aFeatures, anEvent);
           Events_Loop::loop()->flush(anEvent);
@@ -382,7 +382,7 @@ bool SketchSolver_Manager::moveAttribute(
 //  Purpose:  search groups of entities interacting with given feature
 // ============================================================================
 SketchGroupPtr SketchSolver_Manager::findGroup(
-    std::shared_ptr<SketchPlugin_Feature> theFeature)
+  std::shared_ptr<SketchPlugin_Feature> theFeature)
 {
   if (!isFeatureValid(theFeature))
     return SketchGroupPtr(); // do not process wrong features
@@ -398,17 +398,21 @@ SketchGroupPtr SketchSolver_Manager::findGroup(
       break;
     }
   }
+  return findGroup(aSketch);
+}
 
-  if (!aSketch)
+SketchGroupPtr SketchSolver_Manager::findGroup(CompositeFeaturePtr theSketch)
+{
+  if (!theSketch)
     return SketchGroupPtr(); // not a sketch's feature
 
   std::list<SketchGroupPtr>::const_iterator aGroupIt;
   for (aGroupIt = myGroups.begin(); aGroupIt != myGroups.end(); ++aGroupIt)
-    if ((*aGroupIt)->getWorkplane() == aSketch)
+    if ((*aGroupIt)->getWorkplane() == theSketch)
       return *aGroupIt;
 
   // group for the sketch does not created yet
-  SketchGroupPtr aNewGroup = SketchGroupPtr(new SketchSolver_Group(aSketch));
+  SketchGroupPtr aNewGroup = SketchGroupPtr(new SketchSolver_Group(theSketch));
   myGroups.push_back(aNewGroup);
   return aNewGroup;
 }
index ce83c3d9b9355c01143917f250c8c47e0200b1aa..78ddaefbb26c2d99811bb51d0462d4564519ace8 100644 (file)
@@ -112,6 +112,11 @@ private:
    *  \return Pointer to corresponding group or NULL if the group cannot be created.
    */
   SketchGroupPtr findGroup(std::shared_ptr<SketchPlugin_Feature> theFeature);
+  /** \brief Searches group related to specified composite feature
+   *  \param[in]  theSketch  sketch to be found
+   *  \return Pointer to corresponding group or NULL if the group cannot be created.
+   */
+  SketchGroupPtr findGroup(std::shared_ptr<ModelAPI_CompositeFeature> theSketch);
 
   /// \brief Stop sending the Update event until all features updated
   /// \return \c true, if the last flushed event is Update