Salome HOME
0c1584873293aa8b5ffe609da08dca24f87d31f0
[modules/shaper.git] / src / SketchSolver / PlaneGCSSolver / PlaneGCSSolver_Solver.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:    PlaneGCSSolver_Solver.cpp
4 // Created: 14 Dec 2014
5 // Author:  Artem ZHIDKOV
6
7 #include <PlaneGCSSolver_Solver.h>
8 #include <Events_LongOp.h>
9
10
11 PlaneGCSSolver_Solver::PlaneGCSSolver_Solver()
12   : myEquationSystem(new GCS::System),
13     myDiagnoseBeforeSolve(false),
14     myInitilized(false),
15     myConfCollected(false),
16     myDOF(0),
17     myFictiveConstraint(0)
18 {
19 }
20
21 PlaneGCSSolver_Solver::~PlaneGCSSolver_Solver()
22 {
23   clear();
24 }
25
26 void PlaneGCSSolver_Solver::clear()
27 {
28   myEquationSystem->clear();
29   myParameters.clear();
30   myConstraints.clear();
31   myConflictingIDs.clear();
32   myDOF = 0;
33
34   removeFictiveConstraint();
35 }
36
37 void PlaneGCSSolver_Solver::addConstraint(GCSConstraintPtr theConstraint)
38 {
39   myEquationSystem->addConstraint(theConstraint.get());
40   myConstraints[theConstraint->getTag()].insert(theConstraint);
41   myDOF = -1;
42 }
43
44 void PlaneGCSSolver_Solver::removeConstraint(ConstraintID theID)
45 {
46   myConstraints.erase(theID);
47   if (myConstraints.empty()) {
48     myEquationSystem->clear();
49     myDOF = (int)myParameters.size();
50   } else {
51     myEquationSystem->clearByTag(theID);
52     myDOF = -1;
53   }
54 }
55
56 double* PlaneGCSSolver_Solver::createParameter()
57 {
58   double* aResult = new double(0);
59   myParameters.push_back(aResult);
60   if (myConstraints.empty() && myDOF >= 0)
61     ++myDOF; // calculate DoF by hand if and only if there is no constraints yet
62   else
63     myDiagnoseBeforeSolve = true;
64   return aResult;
65 }
66
67 void PlaneGCSSolver_Solver::removeParameters(const GCS::SET_pD& theParams)
68 {
69   for (int i = (int)myParameters.size() - 1; i >= 0; --i)
70     if (theParams.find(myParameters[i]) != theParams.end()) {
71       myParameters.erase(myParameters.begin() + i);
72       --myDOF;
73     }
74 }
75
76 void PlaneGCSSolver_Solver::initialize()
77 {
78   Events_LongOp::start(this);
79   addFictiveConstraintIfNecessary();
80   if (myDiagnoseBeforeSolve)
81     diagnose();
82   myEquationSystem->declareUnknowns(myParameters);
83   myEquationSystem->initSolution();
84   Events_LongOp::end(this);
85
86   myInitilized = true;
87 }
88
89 PlaneGCSSolver_Solver::SolveStatus PlaneGCSSolver_Solver::solve()
90 {
91   // clear list of conflicting constraints
92   if (myConfCollected) {
93     myConflictingIDs.clear();
94     myConfCollected = false;
95   }
96
97   if (myParameters.empty())
98     return STATUS_INCONSISTENT;
99
100   GCS::SolveStatus aResult = GCS::Success;
101   Events_LongOp::start(this);
102   if (myInitilized) {
103     aResult = (GCS::SolveStatus)myEquationSystem->solve();
104   } else {
105     addFictiveConstraintIfNecessary();
106
107     if (myDiagnoseBeforeSolve)
108       diagnose();
109     aResult = (GCS::SolveStatus)myEquationSystem->solve(myParameters);
110   }
111   Events_LongOp::end(this);
112
113   // collect information about conflicting constraints every time,
114   // sometimes solver reports about succeeded recalculation but has conflicting constraints
115   // (for example, apply horizontal constraint for a copied feature)
116   collectConflicting();
117   if (!myConflictingIDs.empty())
118     aResult = GCS::Failed;
119
120   SolveStatus aStatus;
121   if (aResult == GCS::Failed)
122     aStatus = STATUS_FAILED;
123   else {
124     myEquationSystem->applySolution();
125     if (myDOF < 0)
126       myDOF = myEquationSystem->dofsNumber();
127     aStatus = STATUS_OK;
128   }
129
130   removeFictiveConstraint();
131   myInitilized = false;
132   return aStatus;
133 }
134
135 void PlaneGCSSolver_Solver::undo()
136 {
137   myEquationSystem->undoSolution();
138 }
139
140 bool PlaneGCSSolver_Solver::isConflicting(const ConstraintID& theConstraint) const
141 {
142   if (!myConfCollected)
143     const_cast<PlaneGCSSolver_Solver*>(this)->collectConflicting();
144   return myConflictingIDs.find((int)theConstraint) != myConflictingIDs.end();
145 }
146
147 void PlaneGCSSolver_Solver::collectConflicting()
148 {
149   GCS::VEC_I aConflict;
150   myEquationSystem->getConflicting(aConflict);
151   myConflictingIDs.insert(aConflict.begin(), aConflict.end());
152
153   myEquationSystem->getRedundant(aConflict);
154   myConflictingIDs.insert(aConflict.begin(), aConflict.end());
155
156   myConfCollected = true;
157 }
158
159 int PlaneGCSSolver_Solver::dof()
160 {
161   if (myDOF < 0 && !myConstraints.empty())
162     diagnose();
163   return myDOF;
164 }
165
166 void PlaneGCSSolver_Solver::diagnose()
167 {
168   myEquationSystem->declareUnknowns(myParameters);
169   myDOF = myEquationSystem->diagnose();
170   myDiagnoseBeforeSolve = false;
171 }
172
173 void PlaneGCSSolver_Solver::addFictiveConstraintIfNecessary()
174 {
175   if (!myConstraints.empty() &&
176       myConstraints.find(CID_MOVEMENT) == myConstraints.end())
177     return;
178
179   if (myFictiveConstraint)
180     return; // no need several fictive constraints
181
182   double* aParam = createParameter();
183   double* aFictiveParameter = new double(0.0);
184
185   myFictiveConstraint = new GCS::ConstraintEqual(aFictiveParameter, aParam);
186   myFictiveConstraint->setTag(CID_FICTIVE);
187   myEquationSystem->addConstraint(myFictiveConstraint);
188 }
189
190 void PlaneGCSSolver_Solver::removeFictiveConstraint()
191 {
192   if (myFictiveConstraint) {
193     myEquationSystem->removeConstraint(myFictiveConstraint);
194     myParameters.pop_back();
195
196     GCS::VEC_pD aParams = myFictiveConstraint->params();
197     for (GCS::VEC_pD::iterator anIt = aParams.begin(); anIt != aParams.end(); ++ anIt)
198       delete *anIt;
199     delete myFictiveConstraint;
200     myFictiveConstraint = 0;
201   }
202 }