From 4b5708fbc546999d5d08899879dd7fb32e87ba3e Mon Sep 17 00:00:00 2001 From: azv Date: Mon, 14 Oct 2019 17:01:33 +0300 Subject: [PATCH] Task 2.5 Show where the remaining degrees of freedom are (issue #2997) * Complete searching the non-constrained entities. * Create unit test. --- src/Events/Events.i | 19 +++++- src/Events/Events_Listener.h | 4 +- src/GeomDataAPI/CMakeLists.txt | 1 + src/GeomDataAPI/GeomDataAPI_swig.h | 1 + src/ModelAPI/CMakeLists.txt | 2 +- src/ModelAPI/ModelAPI.i | 6 ++ src/ModelAPI/ModelAPI_swig.h | 1 + src/PartSet/PartSet_WidgetSketchLabel.cpp | 2 +- src/SketchPlugin/CMakeLists.txt | 1 + src/SketchPlugin/Test/TestRemainingDoF.py | 65 +++++++++++++++++++ .../PlaneGCSSolver/PlaneGCSSolver_Solver.cpp | 26 ++++++-- .../PlaneGCSSolver/PlaneGCSSolver_Solver.h | 4 +- src/SketchSolver/SketchSolver_Manager.cpp | 18 +++-- src/SketchSolver/SketchSolver_Manager.h | 5 ++ 14 files changed, 138 insertions(+), 17 deletions(-) create mode 100644 src/SketchPlugin/Test/TestRemainingDoF.py diff --git a/src/Events/Events.i b/src/Events/Events.i index aa09fbbee..5b543e58c 100644 --- a/src/Events/Events.i +++ b/src/Events/Events.i @@ -18,11 +18,22 @@ // /* 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" %} @@ -33,6 +44,12 @@ %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" diff --git a/src/Events/Events_Listener.h b/src/Events/Events_Listener.h index 07fd93f97..a7da686f6 100644 --- a/src/Events/Events_Listener.h +++ b/src/Events/Events_Listener.h @@ -38,7 +38,9 @@ class Events_Listener { /// map from event ID to groupped messages (for flush for groupMessages=true listeners) std::map > 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& theMessage) = 0; diff --git a/src/GeomDataAPI/CMakeLists.txt b/src/GeomDataAPI/CMakeLists.txt index fa7830d93..ecc087c26 100644 --- a/src/GeomDataAPI/CMakeLists.txt +++ b/src/GeomDataAPI/CMakeLists.txt @@ -41,6 +41,7 @@ SET(PROJECT_LIBRARIES INCLUDE_DIRECTORIES( ../GeomAPI # only for SWIG + ../Events # only for SWIG ../ModelAPI ) diff --git a/src/GeomDataAPI/GeomDataAPI_swig.h b/src/GeomDataAPI/GeomDataAPI_swig.h index df13808e4..b23de6016 100644 --- a/src/GeomDataAPI/GeomDataAPI_swig.h +++ b/src/GeomDataAPI/GeomDataAPI_swig.h @@ -22,6 +22,7 @@ #include #include + #include #include "GeomDataAPI.h" #include "GeomDataAPI_Point.h" diff --git a/src/ModelAPI/CMakeLists.txt b/src/ModelAPI/CMakeLists.txt index 1ef43263f..a1894001e 100644 --- a/src/ModelAPI/CMakeLists.txt +++ b/src/ModelAPI/CMakeLists.txt @@ -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}) diff --git a/src/ModelAPI/ModelAPI.i b/src/ModelAPI/ModelAPI.i index dc76645c8..913b41b8b 100644 --- a/src/ModelAPI/ModelAPI.i +++ b/src/ModelAPI/ModelAPI.i @@ -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; @@ -125,6 +127,7 @@ // all supported interfaces %include "ModelAPI_Entity.h" +%include "ModelAPI_Events.h" %include "ModelAPI_Document.h" %include "ModelAPI_Session.h" %include "ModelAPI_Plugin.h" @@ -175,6 +178,7 @@ // std::set -> [] %template(AttributeSet) std::set >; %template(FeatureSet) std::set >; +%template(ObjectSet) std::set >; // std::dynamic_pointer_cast template std::shared_ptr shared_ptr_cast(std::shared_ptr theObject); @@ -192,6 +196,8 @@ template std::shared_ptr shared_ptr_cast(std::shared_ptr %template(modelAPI_ResultGroup) shared_ptr_cast; %template(modelAPI_ResultField) shared_ptr_cast; +%template(messageToUpdatedMessage) shared_ptr_cast; + // Attribute casts %template(modelAPI_AttributeDocRef) shared_ptr_cast; %template(modelAPI_AttributeDouble) shared_ptr_cast; diff --git a/src/ModelAPI/ModelAPI_swig.h b/src/ModelAPI/ModelAPI_swig.h index 2187c2ae4..de4312c62 100644 --- a/src/ModelAPI/ModelAPI_swig.h +++ b/src/ModelAPI/ModelAPI_swig.h @@ -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" diff --git a/src/PartSet/PartSet_WidgetSketchLabel.cpp b/src/PartSet/PartSet_WidgetSketchLabel.cpp index 1cdd66a5c..60de04c91 100644 --- a/src/PartSet/PartSet_WidgetSketchLabel.cpp +++ b/src/PartSet/PartSet_WidgetSketchLabel.cpp @@ -780,7 +780,7 @@ void PartSet_WidgetSketchLabel::onShowDOF() CompositeFeaturePtr aCompFeature = std::dynamic_pointer_cast(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); } } diff --git a/src/SketchPlugin/CMakeLists.txt b/src/SketchPlugin/CMakeLists.txt index 1edde96b7..1e7a20b4e 100644 --- a/src/SketchPlugin/CMakeLists.txt +++ b/src/SketchPlugin/CMakeLists.txt @@ -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 index 000000000..539c2dfbf --- /dev/null +++ b/src/SketchPlugin/Test/TestRemainingDoF.py @@ -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) diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.cpp index cfa6ccccb..30b12ec7b 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.cpp @@ -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::iterator anIt = aFound->second.begin(); + for (std::list::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() diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.h index e6c1b4ba5..290136b25 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.h +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.h @@ -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 > ConstraintMap; + typedef std::map > ConstraintMap; GCS::VEC_pD myParameters; ///< list of unknowns ConstraintMap myConstraints; ///< list of constraints diff --git a/src/SketchSolver/SketchSolver_Manager.cpp b/src/SketchSolver/SketchSolver_Manager.cpp index 6f000ec6c..a9d47533e 100644 --- a/src/SketchSolver/SketchSolver_Manager.cpp +++ b/src/SketchSolver/SketchSolver_Manager.cpp @@ -231,8 +231,8 @@ void SketchSolver_Manager::processEvent( if (aObjects.size() == 1) { std::set::const_iterator aIt; for (aIt = aObjects.cbegin(); aIt != aObjects.cend(); aIt++) { - std::shared_ptr aFeature = - std::dynamic_pointer_cast(*aIt); + CompositeFeaturePtr aFeature = + std::dynamic_pointer_cast(*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 theFeature) + std::shared_ptr 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::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; } diff --git a/src/SketchSolver/SketchSolver_Manager.h b/src/SketchSolver/SketchSolver_Manager.h index ce83c3d9b..78ddaefbb 100644 --- a/src/SketchSolver/SketchSolver_Manager.h +++ b/src/SketchSolver/SketchSolver_Manager.h @@ -112,6 +112,11 @@ private: * \return Pointer to corresponding group or NULL if the group cannot be created. */ SketchGroupPtr findGroup(std::shared_ptr 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 theSketch); /// \brief Stop sending the Update event until all features updated /// \return \c true, if the last flushed event is Update -- 2.39.2