1 // Copyright (C) 2014-2017 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
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
21 #include <PlaneGCSSolver_Solver.h>
22 #include <Events_LongOp.h>
24 // Multiplier to correlate IDs of SketchPlugin constraint and primitive PlaneGCS constraints
25 static const int THE_CONSTRAINT_MULT = 10;
28 PlaneGCSSolver_Solver::PlaneGCSSolver_Solver()
29 : myEquationSystem(new GCS::System),
30 myDiagnoseBeforeSolve(false),
32 myConfCollected(false),
34 myFictiveConstraint(0)
38 PlaneGCSSolver_Solver::~PlaneGCSSolver_Solver()
43 void PlaneGCSSolver_Solver::clear()
45 myEquationSystem->clear();
47 myConstraints.clear();
48 myConflictingIDs.clear();
51 removeFictiveConstraint();
54 void PlaneGCSSolver_Solver::addConstraint(const ConstraintID& theMultiConstraintID,
55 const std::list<GCSConstraintPtr>& theConstraints)
57 int anID = theMultiConstraintID > CID_UNKNOWN ?
58 theMultiConstraintID * THE_CONSTRAINT_MULT :
61 for (std::list<GCSConstraintPtr>::const_iterator anIt = theConstraints.begin();
62 anIt != theConstraints.end(); ++anIt) {
63 GCSConstraintPtr aConstraint = *anIt;
64 aConstraint->setTag(anID);
65 myEquationSystem->addConstraint(aConstraint.get());
66 myConstraints[theMultiConstraintID].insert(aConstraint);
68 if (anID > CID_UNKNOWN)
72 if (theMultiConstraintID >= CID_UNKNOWN)
77 void PlaneGCSSolver_Solver::removeConstraint(const ConstraintID& theID)
79 ConstraintMap::iterator aFound = myConstraints.find(theID);
80 if (aFound != myConstraints.end()) {
81 for (std::set<GCSConstraintPtr>::iterator anIt = aFound->second.begin();
82 anIt != aFound->second.end(); ++anIt)
83 myEquationSystem->clearByTag((*anIt)->getTag());
85 myConstraints.erase(aFound);
88 if (myConstraints.empty()) {
89 myEquationSystem->clear();
90 myDOF = (int)myParameters.size();
91 } else if (theID >= CID_UNKNOWN)
97 double* PlaneGCSSolver_Solver::createParameter()
99 double* aResult = new double(0);
100 myParameters.push_back(aResult);
101 if (myConstraints.empty() && myDOF >= 0)
102 ++myDOF; // calculate DoF by hand if and only if there is no constraints yet
104 myDiagnoseBeforeSolve = true;
108 void PlaneGCSSolver_Solver::addParameters(const GCS::SET_pD& theParams)
110 GCS::SET_pD aParams(theParams);
111 // leave new parameters only
112 GCS::VEC_pD::iterator anIt = myParameters.begin();
113 for (; anIt != myParameters.end(); ++anIt)
114 if (aParams.find(*anIt) != aParams.end())
115 aParams.erase(*anIt);
117 myParameters.insert(myParameters.end(), aParams.begin(), aParams.end());
118 if (myConstraints.empty() && myDOF >=0)
119 myDOF += (int)aParams.size(); // calculate DoF by hand only if there is no constraints yet
121 myDiagnoseBeforeSolve = true;
124 void PlaneGCSSolver_Solver::removeParameters(const GCS::SET_pD& theParams)
126 for (int i = (int)myParameters.size() - 1; i >= 0; --i)
127 if (theParams.find(myParameters[i]) != theParams.end()) {
128 myParameters.erase(myParameters.begin() + i);
131 if (!myConstraints.empty())
132 myDiagnoseBeforeSolve = true;
135 void PlaneGCSSolver_Solver::initialize()
137 Events_LongOp::start(this);
138 addFictiveConstraintIfNecessary();
139 if (myDiagnoseBeforeSolve)
141 myEquationSystem->declareUnknowns(myParameters);
142 myEquationSystem->initSolution();
143 Events_LongOp::end(this);
148 PlaneGCSSolver_Solver::SolveStatus PlaneGCSSolver_Solver::solve()
150 // clear list of conflicting constraints
151 if (myConfCollected) {
152 myConflictingIDs.clear();
153 myConfCollected = false;
156 if (myParameters.empty())
157 return myConstraints.empty() ? STATUS_OK : STATUS_INCONSISTENT;
159 GCS::SolveStatus aResult = GCS::Success;
160 Events_LongOp::start(this);
162 aResult = (GCS::SolveStatus)myEquationSystem->solve();
164 addFictiveConstraintIfNecessary();
166 aResult = (GCS::SolveStatus)myEquationSystem->solve(myParameters);
169 if (aResult == GCS::Failed) {
170 // DogLeg solver failed without conflicting constraints, try to use Levenberg-Marquardt solver
171 aResult = (GCS::SolveStatus)myEquationSystem->solve(myParameters, true,
172 GCS::LevenbergMarquardt);
174 Events_LongOp::end(this);
176 // collect information about conflicting constraints every time,
177 // sometimes solver reports about succeeded recalculation but has conflicting constraints
178 // (for example, apply horizontal constraint for a copied feature)
179 collectConflicting();
180 if (!myConflictingIDs.empty())
181 aResult = GCS::Failed;
184 if (aResult == GCS::Failed)
185 aStatus = STATUS_FAILED;
187 myEquationSystem->applySolution();
189 myDOF = myEquationSystem->dofsNumber();
193 removeFictiveConstraint();
194 myInitilized = false;
198 void PlaneGCSSolver_Solver::undo()
200 myEquationSystem->undoSolution();
203 bool PlaneGCSSolver_Solver::isConflicting(const ConstraintID& theConstraint) const
205 if (!myConfCollected)
206 const_cast<PlaneGCSSolver_Solver*>(this)->collectConflicting();
207 return myConflictingIDs.find((int)theConstraint) != myConflictingIDs.end();
210 void PlaneGCSSolver_Solver::collectConflicting(bool withRedundant)
212 GCS::VEC_I aConflict;
213 myEquationSystem->getConflicting(aConflict);
214 // convert PlaneGCS constraint IDs to SketchPlugin's ID
215 for (GCS::VEC_I::const_iterator anIt = aConflict.begin(); anIt != aConflict.end(); ++anIt)
216 myConflictingIDs.insert((*anIt) / THE_CONSTRAINT_MULT);
219 myEquationSystem->getRedundant(aConflict);
220 // convert PlaneGCS constraint IDs to SketchPlugin's ID
221 for (GCS::VEC_I::const_iterator anIt = aConflict.begin(); anIt != aConflict.end(); ++anIt)
222 myConflictingIDs.insert((*anIt) / THE_CONSTRAINT_MULT);
225 myConfCollected = true;
228 int PlaneGCSSolver_Solver::dof()
230 if (myDOF < 0 && !myConstraints.empty())
235 void PlaneGCSSolver_Solver::diagnose()
237 myEquationSystem->declareUnknowns(myParameters);
238 myDOF = myEquationSystem->diagnose();
239 myDiagnoseBeforeSolve = false;
242 void PlaneGCSSolver_Solver::addFictiveConstraintIfNecessary()
244 if (!myConstraints.empty() &&
245 myConstraints.find(CID_MOVEMENT) == myConstraints.end())
248 if (myFictiveConstraint)
249 return; // no need several fictive constraints
252 double* aParam = createParameter();
253 double* aFictiveParameter = new double(0.0);
255 myFictiveConstraint = new GCS::ConstraintEqual(aFictiveParameter, aParam);
256 myFictiveConstraint->setTag(CID_FICTIVE);
257 myEquationSystem->addConstraint(myFictiveConstraint);
258 // DoF should not be changed when adding fictive constraint
262 void PlaneGCSSolver_Solver::removeFictiveConstraint()
264 if (myFictiveConstraint) {
265 myEquationSystem->removeConstraint(myFictiveConstraint);
266 myParameters.pop_back();
268 GCS::VEC_pD aParams = myFictiveConstraint->params();
269 for (GCS::VEC_pD::iterator anIt = aParams.begin(); anIt != aParams.end(); ++ anIt)
271 delete myFictiveConstraint;
272 myFictiveConstraint = 0;