From 82431fcacb9e3b6f5dfc882b01cd739160856d9e Mon Sep 17 00:00:00 2001 From: azv Date: Tue, 26 Nov 2019 19:03:03 +0300 Subject: [PATCH] Issue #3087: Show remaining DoFs highlight not all features Find all parameters coincident to the returned by PlaneGCS. --- src/SketchPlugin/CMakeLists.txt | 2 + src/SketchPlugin/Test/Test3087_1.py | 63 ++++++++++++++++ src/SketchPlugin/Test/Test3087_2.py | 66 +++++++++++++++++ .../PlaneGCSSolver/PlaneGCSSolver_Solver.cpp | 73 ++++++++++++++++++- .../PlaneGCSSolver/PlaneGCSSolver_Solver.h | 2 +- .../PlaneGCSSolver/PlaneGCSSolver_Storage.cpp | 15 ++-- 6 files changed, 207 insertions(+), 14 deletions(-) create mode 100644 src/SketchPlugin/Test/Test3087_1.py create mode 100644 src/SketchPlugin/Test/Test3087_2.py diff --git a/src/SketchPlugin/CMakeLists.txt b/src/SketchPlugin/CMakeLists.txt index 199149f69..c660b7aeb 100644 --- a/src/SketchPlugin/CMakeLists.txt +++ b/src/SketchPlugin/CMakeLists.txt @@ -203,6 +203,8 @@ ADD_UNIT_TESTS( Test2860.py Test2894.py Test3019.py + Test3087_1.py + Test3087_2.py TestArcBehavior.py TestChangeSketchPlane1.py TestChangeSketchPlane2.py diff --git a/src/SketchPlugin/Test/Test3087_1.py b/src/SketchPlugin/Test/Test3087_1.py new file mode 100644 index 000000000..92a0fe448 --- /dev/null +++ b/src/SketchPlugin/Test/Test3087_1.py @@ -0,0 +1,63 @@ +# 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) == 3) + self.myEventProcessed = True + + +if __name__ == "__main__": + # create the listener + listener = FreeShapesListener() + + model.begin() + partSet = model.moduleDocument() + Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY")) + SketchLine_1 = Sketch_1.addLine(10, 10, -10, 10) + SketchLine_2 = Sketch_1.addLine(-10, 10, -10, -10) + SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint()) + SketchLine_3 = Sketch_1.addLine(-10, -10, 10, -10) + SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint()) + SketchConstraintRigid_1 = Sketch_1.setFixed(SketchLine_1.startPoint()) + SketchConstraintRigid_2 = Sketch_1.setFixed(SketchLine_3.endPoint()) + 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/SketchPlugin/Test/Test3087_2.py b/src/SketchPlugin/Test/Test3087_2.py new file mode 100644 index 000000000..4fb18ea66 --- /dev/null +++ b/src/SketchPlugin/Test/Test3087_2.py @@ -0,0 +1,66 @@ +# 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) == 4) + self.myEventProcessed = True + + +if __name__ == "__main__": + # create the listener + listener = FreeShapesListener() + + model.begin() + partSet = model.moduleDocument() + Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY")) + SketchLine_1 = Sketch_1.addLine(10, 10, -10, 10) + SketchLine_2 = Sketch_1.addLine(-10, 10, -10, -10) + SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint()) + SketchLine_3 = Sketch_1.addLine(-10, -10, 10, -10) + SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint()) + SketchConstraintRigid_1 = Sketch_1.setFixed(SketchLine_1.startPoint()) + SketchConstraintRigid_2 = Sketch_1.setFixed(SketchLine_3.endPoint()) + SketchCircle_1 = Sketch_1.addCircle(-10, 10, 10) + SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchCircle_1.center()) + SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 10) + 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 30b12ec7b..716022c98 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.cpp @@ -243,10 +243,10 @@ void PlaneGCSSolver_Solver::diagnose(const GCS::Algorithm& theAlgo) myDiagnoseBeforeSolve = false; } -void PlaneGCSSolver_Solver::getFreeParameters(GCS::VEC_pD& theFreeParams) +void PlaneGCSSolver_Solver::getFreeParameters(GCS::SET_pD& theFreeParams) { if (myConstraints.empty()) - theFreeParams = myParameters; + theFreeParams.insert(myParameters.begin(), myParameters.end()); else { GCS::VEC_pD aParametersCopy = myParameters; ConstraintMap aConstraintCopy = myConstraints; @@ -263,10 +263,77 @@ void PlaneGCSSolver_Solver::getFreeParameters(GCS::VEC_pD& theFreeParams) GCS::QRAlgorithm aQRAlgo = myEquationSystem->qrAlgorithm; myEquationSystem->qrAlgorithm = GCS::EigenDenseQR; diagnose(); - myEquationSystem->getDependentParams(theFreeParams); + GCS::VEC_pD aFreeParams; + myEquationSystem->getDependentParams(aFreeParams); + theFreeParams.insert(aFreeParams.begin(), aFreeParams.end()); // revert QR decomposition algorithm myEquationSystem->qrAlgorithm = aQRAlgo; } + + if (theFreeParams.empty()) + return; + + // find all equal parameters too + struct EqualParameters + { + typedef std::map::iterator> MapParamGroup; + + std::list myEqualParams; + MapParamGroup myGroups; + + void add(double* theParam1, double* theParam2) + { + MapParamGroup::iterator aFound1 = myGroups.find(theParam1); + MapParamGroup::iterator aFound2 = myGroups.find(theParam2); + + if (aFound1 == myGroups.end()) { + if (aFound2 == myGroups.end()) { + // create new group + myEqualParams.push_back(GCS::SET_pD()); + std::list::iterator aGroup = --myEqualParams.end(); + aGroup->insert(theParam1); + aGroup->insert(theParam2); + myGroups[theParam1] = aGroup; + myGroups[theParam2] = aGroup; + } + else { + // add first parameter to the second group + aFound2->second->insert(theParam1); + myGroups[theParam1] = aFound2->second; + } + } + else { + if (aFound2 == myGroups.end()) { + // add second parameter to the first group + aFound1->second->insert(theParam2); + myGroups[theParam2] = aFound1->second; + } + else if (aFound1 != aFound2) { + // merge two groups + GCS::SET_pD aCopy = *(aFound2->second); + myEqualParams.erase(aFound2->second); + for (GCS::SET_pD::iterator anIt = aCopy.begin(); anIt != aCopy.end(); ++anIt) + myGroups[*anIt] = aFound1->second; + aFound1->second->insert(aCopy.begin(), aCopy.end()); + } + } + } + } anEqualParams; + + for (ConstraintMap::iterator anIt = myConstraints.begin(); anIt != myConstraints.end(); ++anIt) + for (std::list::iterator aCIt = anIt->second.begin(); + aCIt != anIt->second.end(); ++aCIt) { + if ((*aCIt)->getTypeId() == GCS::Equal) + anEqualParams.add((*aCIt)->params()[0], (*aCIt)->params()[1]); + } + + GCS::SET_pD aFreeParamsCopy = theFreeParams; + for (GCS::SET_pD::iterator anIt = aFreeParamsCopy.begin(); + anIt != aFreeParamsCopy.end(); ++anIt) { + EqualParameters::MapParamGroup::iterator aFound = anEqualParams.myGroups.find(*anIt); + if (aFound != anEqualParams.myGroups.end()) + theFreeParams.insert(aFound->second->begin(), aFound->second->end()); + } } void PlaneGCSSolver_Solver::addFictiveConstraintIfNecessary() diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.h index 290136b25..96c198dbb 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); + void getFreeParameters(GCS::SET_pD& theFreeParams); /// \brief Degrees of freedom int dof(); diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp index 833e15352..a5788f23a 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp @@ -658,25 +658,20 @@ PlaneGCSSolver_Solver::SolveStatus PlaneGCSSolver_Storage::checkDegeneratedGeome void PlaneGCSSolver_Storage::getUnderconstrainedGeometry(std::set& theFeatures) const { - std::vector aFreeParams; + std::set aFreeParams; mySketchSolver->getFreeParameters(aFreeParams); if (aFreeParams.empty()) return; - std::map aParamOfFeatures; for (std::map::const_iterator aFIt = myFeatureMap.begin(); aFIt != myFeatureMap.end(); ++aFIt) { if (!aFIt->second) continue; GCS::SET_pD aParams = PlaneGCSSolver_Tools::parameters(aFIt->second); for (GCS::SET_pD::iterator aPIt = aParams.begin(); aPIt != aParams.end(); ++aPIt) - aParamOfFeatures[*aPIt] = aFIt->first; - } - - for (std::vector::iterator anIt = aFreeParams.begin(); - anIt != aFreeParams.end(); ++anIt) { - std::map::iterator aFound = aParamOfFeatures.find(*anIt); - if (aFound != aParamOfFeatures.end()) - theFeatures.insert(aFound->second); + if (aFreeParams.find(*aPIt) != aFreeParams.end()) { + theFeatures.insert(aFIt->first); + break; + } } } -- 2.39.2