1 // Copyright (C) 2014-2019 CEA/DEN, EDF R&D
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #include <PlaneGCSSolver_Solver.h>
21 #include <Events_LongOp.h>
23 // Multiplier to correlate IDs of SketchPlugin constraint and primitive PlaneGCS constraints
24 static const int THE_CONSTRAINT_MULT = 100;
27 PlaneGCSSolver_Solver::PlaneGCSSolver_Solver()
28 : myEquationSystem(new GCS::System),
29 myDiagnoseBeforeSolve(false),
31 myConfCollected(false),
33 myFictiveConstraint(0)
37 PlaneGCSSolver_Solver::~PlaneGCSSolver_Solver()
42 void PlaneGCSSolver_Solver::clear()
44 myEquationSystem->clear();
46 myConstraints.clear();
47 myConflictingIDs.clear();
50 removeFictiveConstraint();
53 void PlaneGCSSolver_Solver::addConstraint(const ConstraintID& theMultiConstraintID,
54 const std::list<GCSConstraintPtr>& theConstraints)
56 int anID = theMultiConstraintID > CID_UNKNOWN ?
57 theMultiConstraintID * THE_CONSTRAINT_MULT :
60 for (std::list<GCSConstraintPtr>::const_iterator anIt = theConstraints.begin();
61 anIt != theConstraints.end(); ++anIt) {
62 GCSConstraintPtr aConstraint = *anIt;
63 aConstraint->setTag(anID);
64 myEquationSystem->addConstraint(aConstraint.get());
65 myConstraints[theMultiConstraintID].insert(aConstraint);
67 if (anID > CID_UNKNOWN)
71 if (theMultiConstraintID >= CID_UNKNOWN)
76 void PlaneGCSSolver_Solver::removeConstraint(const ConstraintID& theID)
78 ConstraintMap::iterator aFound = myConstraints.find(theID);
79 if (aFound != myConstraints.end()) {
80 for (std::set<GCSConstraintPtr>::iterator anIt = aFound->second.begin();
81 anIt != aFound->second.end(); ++anIt)
82 myEquationSystem->clearByTag((*anIt)->getTag());
84 myConstraints.erase(aFound);
87 if (myConstraints.empty()) {
88 myEquationSystem->clear();
89 myDOF = (int)myParameters.size();
90 } else if (theID >= CID_UNKNOWN)
96 double* PlaneGCSSolver_Solver::createParameter()
98 double* aResult = new double(0);
99 myParameters.push_back(aResult);
100 if (myConstraints.empty() && myDOF >= 0)
101 ++myDOF; // calculate DoF by hand if and only if there is no constraints yet
103 myDiagnoseBeforeSolve = true;
107 void PlaneGCSSolver_Solver::addParameters(const GCS::SET_pD& theParams)
109 GCS::SET_pD aParams(theParams);
110 // leave new parameters only
111 GCS::VEC_pD::iterator anIt = myParameters.begin();
112 for (; anIt != myParameters.end(); ++anIt)
113 if (aParams.find(*anIt) != aParams.end())
114 aParams.erase(*anIt);
116 myParameters.insert(myParameters.end(), aParams.begin(), aParams.end());
117 if (myConstraints.empty() && myDOF >=0)
118 myDOF += (int)aParams.size(); // calculate DoF by hand only if there is no constraints yet
120 myDiagnoseBeforeSolve = true;
123 void PlaneGCSSolver_Solver::removeParameters(const GCS::SET_pD& theParams)
125 for (int i = (int)myParameters.size() - 1; i >= 0; --i)
126 if (theParams.find(myParameters[i]) != theParams.end()) {
127 myParameters.erase(myParameters.begin() + i);
130 if (!myConstraints.empty())
131 myDiagnoseBeforeSolve = true;
134 void PlaneGCSSolver_Solver::initialize()
136 Events_LongOp::start(this);
137 addFictiveConstraintIfNecessary();
138 if (myDiagnoseBeforeSolve)
140 myEquationSystem->declareUnknowns(myParameters);
141 myEquationSystem->initSolution();
142 Events_LongOp::end(this);
147 PlaneGCSSolver_Solver::SolveStatus PlaneGCSSolver_Solver::solve()
149 // clear list of conflicting constraints
150 if (myConfCollected) {
151 myConflictingIDs.clear();
152 myConfCollected = false;
155 if (myParameters.empty())
156 return myConstraints.empty() ? STATUS_OK : STATUS_INCONSISTENT;
158 GCS::SolveStatus aResult = GCS::Success;
159 Events_LongOp::start(this);
161 aResult = (GCS::SolveStatus)myEquationSystem->solve();
163 addFictiveConstraintIfNecessary();
165 aResult = (GCS::SolveStatus)myEquationSystem->solve(myParameters);
168 if (aResult == GCS::Failed) {
169 // DogLeg solver failed without conflicting constraints, try to use Levenberg-Marquardt solver
170 diagnose(GCS::LevenbergMarquardt);
171 aResult = (GCS::SolveStatus)myEquationSystem->solve(myParameters, true,
172 GCS::LevenbergMarquardt);
173 if (aResult == GCS::Failed) {
175 aResult = (GCS::SolveStatus)myEquationSystem->solve(myParameters, true, GCS::BFGS);
178 Events_LongOp::end(this);
180 // collect information about conflicting constraints every time,
181 // sometimes solver reports about succeeded recalculation but has conflicting constraints
182 // (for example, apply horizontal constraint for a copied feature)
183 collectConflicting();
184 if (!myConflictingIDs.empty())
185 aResult = GCS::Failed;
188 if (aResult == GCS::Failed)
189 aStatus = STATUS_FAILED;
191 myEquationSystem->applySolution();
193 myDOF = myEquationSystem->dofsNumber();
197 removeFictiveConstraint();
198 myInitilized = false;
202 void PlaneGCSSolver_Solver::undo()
204 myEquationSystem->undoSolution();
207 bool PlaneGCSSolver_Solver::isConflicting(const ConstraintID& theConstraint) const
209 if (!myConfCollected)
210 const_cast<PlaneGCSSolver_Solver*>(this)->collectConflicting();
211 return myConflictingIDs.find((int)theConstraint) != myConflictingIDs.end();
214 void PlaneGCSSolver_Solver::collectConflicting(bool withRedundant)
216 GCS::VEC_I aConflict;
217 myEquationSystem->getConflicting(aConflict);
218 // convert PlaneGCS constraint IDs to SketchPlugin's ID
219 for (GCS::VEC_I::const_iterator anIt = aConflict.begin(); anIt != aConflict.end(); ++anIt)
220 myConflictingIDs.insert((*anIt) / THE_CONSTRAINT_MULT);
223 myEquationSystem->getRedundant(aConflict);
224 // convert PlaneGCS constraint IDs to SketchPlugin's ID
225 for (GCS::VEC_I::const_iterator anIt = aConflict.begin(); anIt != aConflict.end(); ++anIt)
226 myConflictingIDs.insert((*anIt) / THE_CONSTRAINT_MULT);
229 myConfCollected = true;
232 int PlaneGCSSolver_Solver::dof()
234 if (myDOF < 0 && !myConstraints.empty())
239 void PlaneGCSSolver_Solver::diagnose(const GCS::Algorithm& theAlgo)
241 myEquationSystem->declareUnknowns(myParameters);
242 myDOF = myEquationSystem->diagnose(theAlgo);
243 myDiagnoseBeforeSolve = false;
246 void PlaneGCSSolver_Solver::addFictiveConstraintIfNecessary()
248 if (!myConstraints.empty() &&
249 myConstraints.find(CID_MOVEMENT) == myConstraints.end())
252 if (myFictiveConstraint)
253 return; // no need several fictive constraints
256 double* aParam = createParameter();
257 double* aFictiveParameter = new double(0.0);
259 myFictiveConstraint = new GCS::ConstraintEqual(aFictiveParameter, aParam);
260 myFictiveConstraint->setTag(CID_FICTIVE);
261 myEquationSystem->addConstraint(myFictiveConstraint);
262 // DoF should not be changed when adding fictive constraint
266 void PlaneGCSSolver_Solver::removeFictiveConstraint()
268 if (myFictiveConstraint) {
269 myEquationSystem->removeConstraint(myFictiveConstraint);
270 myParameters.pop_back();
272 GCS::VEC_pD aParams = myFictiveConstraint->params();
273 for (GCS::VEC_pD::iterator anIt = aParams.begin(); anIt != aParams.end(); ++ anIt)
275 delete myFictiveConstraint;
276 myFictiveConstraint = 0;